Skip to content

Commit 1bc7a2d

Browse files
gh-13, gh-14: Allow carets before code notes; add string form to TNS().
1 parent 9fe0e2c commit 1bc7a2d

File tree

5 files changed

+52
-5
lines changed

5 files changed

+52
-5
lines changed

asm-lang.exe

1.29 KB
Binary file not shown.

docs/SPECIFICATION.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575

7676
Keywords: The language's reserved keywords (for example, `IF`, `WHILE`, `FUNC`, etc.) are matched by the lexer exactly as listed in this specification and are case-sensitive. Programs must use the keywords in their canonical uppercase form; otherwise the token will be recognized as an identifier. Built-in operator names such as `INPUT`, `PRINT`, and `IMPORT` follow the same case-sensitive matching rules.
7777

78-
Line continuation: The character `^` serves as a line-continuation marker. When a caret `^` appears in the source and is followed immediately by a newline, both the `^` and the newline are ignored by the lexer (that is, the logical line continues on the next physical line). If a `^` is present in a string, it does not count as a line continuation. If a caret appears and is not immediately followed by a newline (or the platform's single-character newline sequence), the lexer must raise a syntax error.
78+
Line continuation: The character `^` serves as a line-continuation marker. When a caret `^` appears in the source and is followed immediately by a newline, both the `^` and the newline are ignored by the lexer (that is, the logical line continues on the next physical line). The lexer also accepts a caret immediately before a code note (a comment beginning with `#`); in this case the `^`, the comment text up to the line terminator, and the terminating newline are treated as if they were not present. If a `^` is present in a string, it does not count as a line continuation. If a caret appears and is not immediately followed by a newline, a code note, or the platform's single-character newline sequence, the lexer must raise a syntax error.
7979

8080
The character `-` primarily serves as the leading sign of a numeric literal (Section 3.1). When `-` appears immediately before optional whitespace and then binary digits, it is parsed as part of the numeric literal (that is, a signed literal). In other contexts (for example inside an index expression) a single `-` token is recognized as a dash used for slice notation `lo-hi`. If `-` appears in any other unsupported context the lexer must raise a syntax error.
8181

@@ -659,6 +659,8 @@
659659

660660
- `TNS(TNS: shape, ANY: value):TNS` Creates a new `TNS` with the shape described by a 1D `TNS` of positive `INT` lengths, filled with `value`.
661661

662+
- `TNS(STR: string):TNS` Converts a `STR` into a 1-D `TNS` of `STR` characters. Each element of the resulting tensor is a `STR` containing a single character from the input string. For example, `TNS("foo")` yields `["f","o","o"]`.
663+
662664
- `CONV(TNS: x, TNS: kernel, INT: stride_w = 1, INT: stride_h = 1, INT: pad_w = 0, INT: pad_h = 0, TNS: bias = []):TNS` — Extended convolution operator.
663665
664666
- Backward-compatible two-argument form: when called as `CONV(x, kernel)` the operator performs the original N-dimensional discrete convolution and returns a tensor with the same shape as `x`. Requirements and semantics from the original behavior remain unchanged: `kernel` must have the same rank as `x`, every kernel dimension length must be odd (so the kernel has a well-defined center), boundary sampling is clamped to the nearest valid index (replicate padding), and tensor element types must be uniformly `INT` or uniformly `FLT` within each tensor. If both tensors are `INT` the output is `INT`, otherwise the output is `FLT`.

interpreter.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ def __init__(self) -> None:
559559
self._register_custom("SHAPE", 1, 1, self._shape)
560560
self._register_custom("TLEN", 2, 2, self._tlen)
561561
self._register_custom("FILL", 2, 2, self._fill)
562-
self._register_custom("TNS", 2, 2, self._tns)
562+
self._register_custom("TNS", 1, 2, self._tns)
563563
self._register_custom("TINT", 1, 1, self._tint)
564564
self._register_custom("TFLT", 1, 1, self._tflt)
565565
self._register_custom("TSTR", 1, 1, self._tstr)
@@ -3128,8 +3128,22 @@ def _tns(
31283128
___: Environment,
31293129
location: SourceLocation,
31303130
) -> Value:
3131-
shape_val = self._expect_tns(args[0], "TNS", location)
3131+
# New form: TNS(STR: string) -> 1-D TNS of STR characters
3132+
first = self._deref_pointer(args[0], rule="TNS", location=location)
3133+
if first.type == TYPE_STR:
3134+
s = self._expect_str(first, "TNS", location)
3135+
# Create a 1-D tensor of STR elements, one-character strings
3136+
length = len(s)
3137+
data = np.empty(length, dtype=object)
3138+
for i, ch in enumerate(s):
3139+
data[i] = Value(TYPE_STR, ch)
3140+
return Value(TYPE_TNS, Tensor(shape=[length], data=data))
3141+
3142+
# Original form: TNS(TNS: shape, ANY: value)
3143+
shape_val = self._expect_tns(first, "TNS", location)
31323144
shape = self._shape_from_tensor(shape_val, "TNS", location)
3145+
if len(args) < 2:
3146+
raise ASMRuntimeError("TNS expects a fill value when called with a shape", location=location, rewrite_rule="TNS")
31333147
fill_value = args[1]
31343148
tensor = interpreter._make_tensor_from_shape(shape, fill_value, "TNS", location)
31353149
return Value(TYPE_TNS, tensor)

lexer.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,29 @@ def _consume_line_continuation(self) -> None:
391391
if self.index < len(self.text) and self.text[self.index] == "\n":
392392
self._advance()
393393
return
394+
# Allow a caret immediately before a code note (comment starting with '#').
395+
# Treat '^#...<newline>' as a valid line-continuation: consume the '^',
396+
# the comment text up to the line terminator, and then consume the newline.
397+
if ch1 == "#":
398+
# consume '^'
399+
self._advance()
400+
# consume comment text up to but not including the newline
401+
self._consume_comment()
402+
# Now require and consume a line terminator after the comment.
403+
if self.index < self._n and self.text[self.index] == "\n":
404+
self._advance()
405+
return
406+
if self.index < self._n and self.text[self.index] == "\r":
407+
self._advance()
408+
if self.index < self._n and self.text[self.index] == "\n":
409+
self._advance()
410+
return
411+
raise ASMParseError(
412+
f"Invalid line continuation '^' before comment not terminated by newline at {self.filename}:{self.line}:{self.column}"
413+
)
414+
394415
raise ASMParseError(
395-
f"Invalid line continuation '^' not followed by newline at {self.filename}:{self.line}:{self.column}"
416+
f"Invalid line continuation '^' not followed by newline or code note at {self.filename}:{self.line}:{self.column}"
396417
)
397418

398419
@property

test.asmln

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ FUNC BUILTIN_TESTS():INT{
4343
# Line continuation (caret ^) inside a tensor literal and index expressions
4444
TNS: cont = [ ^
4545
[1, 10, 11], ^
46-
[100, 101, 110] ^
46+
[100, 101, 110] ^# carets allowed before code notes
4747
]
4848
ASSERT( EQ( TLEN(cont, 1), 10 ) )
4949
DEL(cont)
@@ -268,6 +268,15 @@ FUNC BUILTIN_TESTS():INT{
268268
ASSERT( EQ( parts[11], "c" ) )
269269
DEL(parts)
270270

271+
# New: TNS from a STR should produce a 1-D tensor of single-character STRs
272+
TNS: chars = TNS("foo")
273+
ASSERT( EQ( TLEN(chars, 1), 11 ) )
274+
ASSERT( EQ( chars[1], "f" ) )
275+
ASSERT( EQ( chars[10], "o" ) )
276+
ASSERT( EQ( chars[11], "o" ) )
277+
ASSERT( EQ( TNS("foo"), ["f","o","o"] ) )
278+
DEL(chars)
279+
271280
# Maps: KEYS/VALUES/KEYIN/VALUEIN/INV and indexed DEL
272281
MAP: mm2 = < "one" = 1, "two" = 10 >
273282
TNS: ks = KEYS(mm2)
@@ -428,6 +437,7 @@ FUNC BUILTIN_TESTS():INT{
428437
}
429438

430439
ASSERT( EQ( IMPORT_PATH(mod_path), 0 ) )
440+
DELETEFILE("tmpmod.asmln")
431441
ASSERT( EQ( tmpmod.v, 1 ) )
432442
ASSERT( EQ( tmpmod.G(), 10 ) )
433443

0 commit comments

Comments
 (0)