19 Incheckningar

Upphovsman SHA1 Meddelande Datum
  MaximeBarniaudy b142d94b11 Delare Stream object in C code and add primitive for stream string matching. Also refactor the rollback mechanism in the grammar parser to give responsibility to the right object. 1 år sedan
  MaximeBarniaudy 1e73ce0d16 Make grammar_parser.meta use the entire grammar from minproto.leg 1 år sedan
  MaximeBarniaudy 0a6802237f Add optional base argument to String.asInteger 1 år sedan
  MaximeBarniaudy e482c081a9 Fix error after single quote semantics change 1 år sedan
  MaximeBarniaudy 45686c7730 Add with and without functions for namespace manimulation, add namespace support to grammars, add test of parser circularity 1 år sedan
  MaximeBarniaudy 23be24b142 parser circularity 1 år sedan
  MaximeBarniaudy 4b1752f399 dotdot got lost in merging 1 år sedan
  MaximeBarniaudy 35fa3e9158 Add Invoke and GetProp 1 år sedan
  MaximeBarniaudy be4e0b8322 Minimal grammar parsing 1 år sedan
  MaximeBarniaudy 7b914a509c Add an intern primitive for symbol creation 1 år sedan
  MaximeBarniaudy 6de35d8a4a Fix range access overshadowing key access 1 år sedan
  WitherFlower dbc8265409 Merge range access and grammar parser changes 1 år sedan
  Ian Piumarta 2171f47dce Fold constants during parsing if FOLDCONST=1. 1 år sedan
  Ian Piumarta 4d396d6170 Fix floating point comparison and assignment operators. 1 år sedan
  Ian Piumarta 883a9cf7c2 Remove let and ::. Add global keyword. Add Ref/Get/SetSym. Cast the 0 terminator in genericError to oop to ensure va_arg picks it up. Better error messages for broken statements in blocks and broken expressions in argument lists. 1 år sedan
  Ian Piumarta ea60878c24 Add exception tests. New test.txt reference output. 1 år sedan
  Ian Piumarta dcbef49750 Exceptions are supported with syntax "try {} catch (e) {}", "try {} ensure {}", and "raise e". Add catch to the list of words that can end an expression statement. Most runtime errors are reported using exceptions when EXCEPTIONS=1. Add String_repeat() supporting multiplying a string and an integer. Illegal escape sequence in a string is a warning not an error. Break and continue work properly in while(). ForFromTo evaluates its start and end arguments. Rename primitive fatal() to error(). 1 år sedan
  Ian Piumarta 207ef22fb0 Upate test reference output. 1 år sedan
  Ian Piumarta 46c7ef6f32 Run the first non-option command line argument as the program. Set _argv__ to program name plus any following command-line arguments. 1 år sedan
7 ändrade filer med 2397 tillägg och 260 borttagningar
Delad Vy
  1. +1079
    -0
      grammar_parser.meta
  2. +805
    -244
      minproto.leg
  3. +73
    -0
      rawMetaGrammar.leg
  4. +78
    -0
      rawgrammar.leg
  5. +255
    -0
      rawminproto.leg
  6. +61
    -14
      test.ref
  7. +46
    -2
      test.txt

+ 1079
- 0
grammar_parser.meta
Filskillnaden har hållits tillbaka eftersom den är för stor
Visa fil


+ 805
- 244
minproto.leg
Filskillnaden har hållits tillbaka eftersom den är för stor
Visa fil


+ 73
- 0
rawMetaGrammar.leg Visa fil

@ -0,0 +1,73 @@
statement = b:block { b; }
| e:expression SEMI { e; }
expression = p:primary
( DOT i:id ASSIGN e:expression # { $$ = newSetProp(p, i, e) }
| LBRAK i:expression RBRAK ASSIGN e:expression { SetArray.new(object: p, index: i, value: e); }
)
| i:id ASSIGN e:expression { SetVar.new(name: i, value: e); }
| pf:postfix { pf; }
postfix = p:primary
( DOT i:id a:args !ASSIGN !LBRACE { p = Invoke.new(self: p, method: i, arguments: a); }
| DOT i:id !ASSIGN { p = GetProp.new(object: p, key: i); }
| a:args !ASSIGN !LBRACE { p = Call.new(function: p, arguments: a); }
) * { p; }
args = LPAREN a:mklist
(
( k:id COLON e:expression { a[k] = e; }
| e:expression { a.push(e); }
)
( COMMA
( k:id COLON e:expression { a[k] = e; }
| e:expression { a.push(e); }
)
) *
) ? RPAREN { a; }
mklist = { Object.new(); }
primary = nil | number | var | subExpr
subExpr = LPAREN e:expression RPAREN { e; }
block = LBRACE b:mklist
( e:statement { b.push(e); }
) * RBRACE { Block.new(body: b); }
nil = NIL { nil; }
number = "-" n:unsign { Unyop.new(operation: __opNeg).push(n) }
| "+" n:number { n }
| n:unsign { n }
unsign = < DIGIT+ > - { yytext.asInteger(10); }
var = i:id { GetVar.new(name: i); }
id = < LETTER ALNUM* > - { intern(yytext); }
DIGIT = [0-9]
LETTER = [A-Za-z_]
ALNUM = LETTER | DIGIT
NIL = "nil" !ALNUM -
SEMI = ";" -
COMMA = "," -
LPAREN = "(" -
RPAREN = ")" -
LBRAK = "[" -
RBRAK = "]" -
LBRACE = "{" -
RBRACE = "}" -
COLON = ":" ![:] -
ASSIGN = "=" ![=] -
DOT = "." ![.] -
- = ( space | comment )*
space = ' ' | '\t' | end-of-line
comment = '//' ( !end-of-line . )* end-of-line
end-of-line = '\r\n' | '\n' | '\r'
end-of-file = !.

+ 78
- 0
rawgrammar.leg Visa fil

@ -0,0 +1,78 @@
grammar = -
( d:definition { set(d.name, d.expression); }
) + end-of-file
definition = i:identifier ASSIGN e:expression SEMI? { Definition.new(name: i, expression: e); }
expression = s:sequence !BAR { s; }
| s1:sequence { s1 = Alternation.new().push(s1); }
( BAR s2:sequence { s1.push(s2); }
) * { s1; }
sequence = p:prefix { p = Sequence.new().push(p); }
( q:prefix { p.push(q); }
) * { p; }
prefix = AND a:action { ParseTimeAction.new(action: a); }
|
( AND s:suffix { And.new(expression: s); }
| NOT s:suffix { Not.new(expression: s); }
| s:suffix { s; }
)
suffix = p:primary
( QUERY { p = Optional.new(expression: p); }
| STAR { p = Star.new(expression: p); }
| PLUS { p = Plus.new(expression: p); }
) ? { p; }
primary = i1:identifier COLON i2:ruleCall !ASSIGN { Assignment.new(name: i1, rule: i2); }
| i:ruleCall !ASSIGN { i; }
| LPAREN e:expression RPAREN { e; }
| l:literal { l; }
| c:class { c; }
| DOT { Dot.new(); }
| a:action { a; }
| BEGIN { Begin.new(); }
| END { End.new(); }
identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { intern(yytext); }
ruleCall = n:identifier CCOLON r:identifier { NamespacedRuleCall.new(namespace: n, name: r); }
| i:identifier { RuleCall.new(name: i); }
literal = ['] < ( !['] char )* > ['] - { StringLiteral.new(string: yytext); }
| ["] < ( !["] char )* > ["] - { StringLiteral.new(string: yytext); }
class = '[' < ( !']' range )* > ']' - { CharacterClass.new(value: yytext); }
range = char '-' char | char
char = '\\' [abefnrtv'"\[\]\\]
| '\\' [0-3][0-7][0-7]
| '\\' [0-7][0-7]?
| !'\\' .
action = m:metaLanguage::block - { Action.new(parseTree: m); }
- = ( space | comment )*
space = ' ' | '\t' | end-of-line
comment = '#' ( !end-of-line . )* end-of-line
end-of-line = '\r\n' | '\n' | '\r'
end-of-file = !.
BAR = '|' -
NOT = '!' -
QUERY = '?' -
BEGIN = '<' -
END = '>' -
SEMI = ";" -
CCOLON = "::" -
LPAREN = "(" -
RPAREN = ")" -
ASSIGN = "=" ![=] -
AND = "&" ![&=] -
PLUS = "+" ![+=] -
STAR = "*" ![=] -
DOT = "." ![.] -
COLON = ":" ![:] -

+ 255
- 0
rawminproto.leg Visa fil

@ -0,0 +1,255 @@
start = - ( s:stmt # { yysval = s }
| !. # { yysval = 0 }
| < (!EOL .)* > # { fatal("syntax error near: %s", yytext) }
)
stmt = LET l:mklet k:id ASSIGN v:expr { l.keyvals.push(k); l.keyvals.push(v) }
( COMMA k:id ASSIGN v:expr { l.keyvals.push(k); l.keyvals.push(v) }
)* SEMI { l }
| WHILE LPAREN c:expr RPAREN s:stmt { While.new(condition: c, body: s) }
| IF LPAREN c:expr RPAREN s:stmt
( ELSE t:stmt { If.new(condition: c, consequent: s, alternate: t ) }
| { If.new(condition: c, consequent: s, alternate: nil) }
)
| CONT EOS { Continue.new() }
| BREAK e:expr EOS { Break.new(value: e) }
| BREAK EOS { Break.new(value: nil) }
| RETURN e:expr EOS { Return.new(value: e) }
| RETURN EOS { Return.new(value: nil) }
| FOR LPAREN i:id IN e:expr RPAREN
s:stmt { ForIn.new(identifier: i, expression: e, body: s) }
| FOR LPAREN i:id FROM a:expr
TO b:expr RPAREN s:stmt { ForFromTo.new(identifier: i, first: a, last: b, body: s) }
| FOR LPAREN i:expr SEMI c:expr SEMI
u:expr RPAREN s:stmt { For.new(initialise: i, condition: c, update: u, body: s) }
| i:id p:params b:block { SetVar.new(name: i, value: Lambda.new(parameters: p, body: b)) }
| v:proto DOT i:id p:params b:block { SetProp.new(object: v, key: i, value: Lambda.new(parameters: p, body: b)) }
| v:proto CCOLON i:id p:params b:block { SetProp.new(object: v, key: i, value: Lambda.new(parameters: p, body: b)) }
| b:block { Block.new(body: b) }
| e:expr EOS { e }
mklet = { Let.new() }
proto = v:var ( DOT j:id !LPAREN { v = GetProp.new(object: v, key: j) }
)* { v }
EOS = SEMI+ | &RBRACE | &ELSE
expr = i:id ASSIGN e:expr { SetVar.new(name: i, value: e) }
| l:logor ( ASSIGN r:expr { l = assign(l, r) }
| PLUSEQ r:expr { l = newBinop(__opPreAdd, lvalue(l), r) }
| MINUSEQ r:expr { l = newBinop(__opPreSub, lvalue(l), r) }
| STAREQ r:expr { l = newBinop(__opPreMul, lvalue(l), r) }
| SLASHEQ r:expr { l = newBinop(__opPreDiv, lvalue(l), r) }
| PCENTEQ r:expr { l = newBinop(__opPreMod, lvalue(l), r) }
| SHLEQ r:expr { l = newBinop(__opPreShl, lvalue(l), r) }
| SHREQ r:expr { l = newBinop(__opPreShr, lvalue(l), r) }
| ANDEQ r:expr { l = newBinop(__opPreAnd, lvalue(l), r) }
| XOREQ r:expr { l = newBinop(__opPreXor, lvalue(l), r) }
| OREQ r:expr { l = newBinop(__opPreOr, lvalue(l), r) }
)? { l }
logor = l:logand ( BARBAR r:logand { l = newBinop(__opLogOr, l, r) }
)* { l }
logand = l:bitor ( ANDAND r:bitor { l = newBinop(__opLogAnd, l, r) }
)* { l }
bitor = l:bitxor ( OR r:bitxor { l = newBinop(__opBitOr, l, r) }
)* { l }
bitxor = l:bitand ( XOR r:bitand { l = newBinop(__opBitXor, l, r) }
)* { l }
bitand = l:eq ( AND r:eq { l = newBinop(__opBitAnd, l, r) }
)* { l }
eq = l:ineq ( EQ r:ineq { l = newBinop(__opEq, l, r) }
| NOTEQ r:ineq { l = newBinop(__opNotEq, l, r) }
)* { l }
ineq = l:shift ( LESS r:shift { l = newBinop(__opLess, l, r) }
| LESSEQ r:shift { l = newBinop(__opLessEq, l, r) }
| GRTREQ r:shift { l = newBinop(__opGrtrEq, l, r) }
| GRTR r:shift { l = newBinop(__opGrtr, l, r) }
)* { l }
shift = l:sum ( SHL r:sum { l = newBinop(__opShl, l, r) }
| SHR r:sum { l = newBinop(__opShr, l, r) }
)* { l }
sum = l:prod ( PLUS r:prod { l = newBinop(__opAdd, l, r) }
| MINUS r:prod { l = newBinop(__opSub, l, r) }
)* { l }
prod = l:range ( STAR r:range { l = newBinop(__opMul, l, r) }
| SLASH r:range { l = newBinop(__opDiv, l, r) }
| PCENT r:range { l = newBinop(__opMod, l, r) }
) * { l }
range = i1:prefix ( DOTDOT i2:prefix { i1 = Range.new(start: i1, end: i2) }
) ? { i1 }
prefix = PPLUS p:prefix { newBinop(__opPreAdd, lvalue(p), 1) }
| MMINUS p:prefix { newBinop(__opPreSub, lvalue(p), 1) }
| PLING p:prefix { Unyop.new(operation: __opNot).push(p) }
| MINUS p:prefix { Unyop.new(operation: __opNeg).push(p) }
| TILDE p:prefix { Unyop.new(operation: __opCom).push(p) }
| BQUOTE s:stmt { Unyop.new(operation: __opQuasiquote).push(s) }
| COMMAT e:expr { Unyop.new(operation: __opUnquote).push(e) }
| postfix
postfix = p:primary
( LBRAK e:expr RBRAK { p = GetArray.new(object: p, index: e) }
| DOT i:id ( a:args !LBRACE { p = Invoke.new(self: p, method: i, arguments: a) }
| { p = GetProp.new(object: p, key: i) }
)
| a:args !LBRACE { p = newApply(p, a) }
| CCOLON i:id { p = GetProp.new(object: p, key: i) }
)*
( PPLUS { p = newBinop(__opPostAdd, lvalue(p), 1) }
| MMINUS { p = newBinop(__opPostAdd, lvalue(p), -1) }
)? { p }
args = LPAREN a:mkobj
( RPAREN
| ( k:id COLON e:expr { a[k] = e }
| e:expr { a.push(e) }
)
( COMMA ( k:id COLON e:expr { a[k] = e }
| e:expr { a.push(e) }
) )* RPAREN ) { a }
params = LPAREN p:mkobj
( RPAREN
| i:id ( COLON e:expr { p[i] = e }
| { p.push(i) }
)
( COMMA i:id ( COLON e:expr { p[i] = e }
| { p.push(i) }
)
)* RPAREN ) { p }
mkobj = { Object.new() }
primary = nil | number | string | symbol | var | lambda | subexpr | literal
lambda = p:params b:block { Lambda.new(parameters: p, body: b) }
subexpr = LPAREN e:expr RPAREN { e }
| b:block { Block.new(body: b) }
literal = LBRAK o:mkobj
( RBRAK
| ( ( i:id COLON e:expr { o[i] = e }
| e:expr { o.push(e) }
) ( COMMA ( i:id COLON e:expr { o[i] = e }
| e:expr { o.push(e) }
) )* )? RBRAK ) { Literal.new(object: o) }
block = LBRACE b:mkobj
( e:stmt { b.push(e) }
)* RBRACE { Block.new(body: b) }
nil = NIL { nil }
number = "-" n:unsign { Unyop.new(operation: __opNeg).push(n) }
| "+" n:number { n }
| n:unsign { n }
unsign = < DIGIT* '.' DIGIT+ EXP? > - { yytext.asFloat() }
| "0" [bB] < BIGIT+ > - { yytext.asInteger(2) }
| "0" [xX] < HIGIT+ > - { yytext.asInteger(16) }
| "0" < OIGIT* > - { yytext.asInteger(8) }
| < DIGIT+ > - { yytext.asInteger() }
string = '"' < ( !'"' char )* > '"' - { yytext.unescaped() }
| "'" < ( !"'" char )* > "'" - { yytext.unescaped() }
char = "\\" ( ["'\\abfnrtv]
| [xX] HIGIT*
| [0-7][0-7]?[0-7]?
)
| .
symbol = HASH i:id { i }
var = i:id { GetVar.new(name: i) }
id = < LETTER ALNUM* > - { intern(yytext) }
BIGIT = [0-1]
OIGIT = [0-7]
DIGIT = [0-9]
HIGIT = [0-9A-Fa-f]
LETTER = [A-Za-z_]
ALNUM = LETTER | DIGIT
SIGN = [-+]
EXP = [eE] SIGN DIGIT+
- = SPACE*
SPACE = [ \t] | EOL | '//' (!EOL .)*
EOL = [\n\r] # { ++lineno }
NIL = "nil" !ALNUM -
WHILE = "while" !ALNUM -
IF = "if" !ALNUM -
ELSE = "else" !ALNUM -
FOR = "for" !ALNUM -
IN = "in" !ALNUM -
FROM = "from" !ALNUM -
TO = "to" !ALNUM -
LET = "let" !ALNUM -
CONT = "continue" !ALNUM -
BREAK = "break" !ALNUM -
RETURN = "return" !ALNUM -
BQUOTE = "`" -
COMMAT = "@" -
HASH = "#" -
SEMI = ";" -
ASSIGN = "=" ![=] -
COMMA = "," -
COLON = ":" ![:] -
CCOLON = "::" -
LPAREN = "(" -
RPAREN = ")" -
LBRAK = "[" -
RBRAK = "]" -
LBRACE = "{" -
RBRACE = "}" -
BARBAR = "||" ![=] -
ANDAND = "&&" ![=] -
OR = "|" ![|=] -
OREQ = "|=" -
XOR = "^" ![=] -
XOREQ = "^=" -
AND = "&" ![&=] -
ANDEQ = "&=" -
EQ = "==" -
NOTEQ = "!=" -
LESS = "<" ![<=] -
LESSEQ = "<=" -
GRTREQ = ">=" -
GRTR = ">" ![=] -
SHL = "<<" ![=] -
SHLEQ = "<<=" -
SHR = ">>" ![=] -
SHREQ = ">>=" -
PLUS = "+" ![+=] -
PLUSEQ = "+=" -
PPLUS = "++" -
MINUS = "-" ![-=] -
MINUSEQ = "-=" -
MMINUS = "--" -
STAR = "*" ![=] -
STAREQ = "*=" -
SLASH = "/" ![/=] -
SLASHEQ = "/=" -
PCENT = "%" ![=] -
PCENTEQ = "%=" -
DOT = "." ![.] -
DOTDOT = ".." -
PLING = "!" ![=] -
TILDE = "~" -

+ 61
- 14
test.ref Visa fil

@ -54,11 +54,14 @@ Point.new(x:3, y:4).magnitude() => 5.000000
| __eval__: <primitive Object.__eval__>
| __name__: Object
| allKeys: <primitive Object.allKeys>
| findKey: <primitive Object.findKey>
| includes: <primitive Object.includes>
| keys: <primitive Object.keys>
| length: <primitive Object.length>
| new: <primitive Object.new>
| pop: <primitive Object.pop>
| push: <primitive Object.push>
| reversed: <primitive Object.reversed>
| sorted: <primitive Object.sorted>
nil no
1 yes
@ -152,6 +155,49 @@ f 102 ( 40 ) 41 32 { 123 32 p 112 r 114 i 105 n 110 t 116 ( 40 _ 95 _ 95 e 1
42
6 * 7
MACRO table <<Object>>
| assert: <<Closure>>
| | environment: nil
| | function: <<Lambda>>
| | | body: <<Object>>
| | | | 0: <<Unyop>>
| | | | | operation: 3
| | | | | 0: <<Block>>
| | | | | | body: <<Object>>
| | | | | | | 0: <<If>>
| | | | | | | | alternate: nil
| | | | | | | | condition: <<Unyop>>
| | | | | | | | | operation: 0
| | | | | | | | | 0: <<Call>>
| | | | | | | | | | arguments: <<Object>>
| | | | | | | | | | | 0: <<Unyop>>
| | | | | | | | | | | | operation: 4
| | | | | | | | | | | | 0: <<GetVar>>
| | | | | | | | | | | | | name: x
| | | | | | | | | | function: <<GetVar>>
| | | | | | | | | | | name: eval
| | | | | | | | consequent: <<Block>>
| | | | | | | | | body: <<Object>>
| | | | | | | | | | 0: <<Call>>
| | | | | | | | | | | arguments: <<Object>>
| | | | | | | | | | | | 0: "\nassertion failed: "
| | | | | | | | | | | | 1: <<Unyop>>
| | | | | | | | | | | | | operation: 4
| | | | | | | | | | | | | 0: <<Call>>
| | | | | | | | | | | | | | arguments: <<Object>>
| | | | | | | | | | | | | | | 0: <<GetVar>>
| | | | | | | | | | | | | | | | name: x
| | | | | | | | | | | | | | function: <<GetVar>>
| | | | | | | | | | | | | | | name: codeString
| | | | | | | | | | | | 2: "\n"
| | | | | | | | | | | function: <<GetVar>>
| | | | | | | | | | | | name: print
| | | | | | | | | | 1: <<Call>>
| | | | | | | | | | | arguments: <<Object>>
| | | | | | | | | | | | 0: 1
| | | | | | | | | | | function: <<GetVar>>
| | | | | | | | | | | | name: exit
| | | parameters: <<Object>>
| | | | 0: x
| test: <<Closure>>
| | environment: nil
| | function: <<Lambda>>
@ -201,17 +247,18 @@ AST eval => 42
0 1 2 3 4 5 6 7 8 9
65 66 67 68 69
1 two 3 four
test.txt:381: *: illegal operand types Integer and String
11: n * factorial(n - 1)
10: if (n < 2) "1" else n * factorial(n - 1)
9: factorial(n - 1)
8: n * factorial(n - 1)
7: if (n < 2) "1" else n * factorial(n - 1)
6: factorial(n - 1)
5: n * factorial(n - 1)
4: if (n < 2) "1" else n * factorial(n - 1)
3: factorial(n - 1)
2: n * factorial(n - 1)
1: if (n < 2) "1" else n * factorial(n - 1)
0: factorial(5)
*: type error: illegal operand types: <Integer> and <Undefined>
13: n * factorial(n - 1)
12: if (n < 2) nil else n * factorial(n - 1)
11: factorial(n - 1)
10: n * factorial(n - 1)
9: if (n < 2) nil else n * factorial(n - 1)
8: factorial(n - 1)
7: n * factorial(n - 1)
6: if (n < 2) nil else n * factorial(n - 1)
5: factorial(n - 1)
4: n * factorial(n - 1)
3: if (n < 2) nil else n * factorial(n - 1)
2: factorial(5)
1: { factorial(5) }
0: try { factorial(5) } catch (e) { { if (!eval(e.__function__ == "*")) { print("\nassertion failed: ", "e.__function__ == \"*\"", "\n"); exit(1) } }; { if (!eval(e.__kind__ == "type error")) { print("\nassertion failed: ", "e.__kind__ == \"type error\"", "\n"); exit(1) } }; { if (!eval(e.__message__ == "illegal operand types")) { print("\nassertion failed: ", "e.__message__ == \"illegal operand types\"", "\n"); exit(1) } }; { if (!eval(e.operand1 == 2)) { print("\nassertion failed: ", "e.operand1 == 2", "\n"); exit(1) } }; { if (!eval(e.operand2 == nil)) { print("\nassertion failed: ", "e.operand2 == nil", "\n"); exit(1) } }; print(e.__function__, ": ", e.__kind__, ": ", e.__message__, ": ", typeName(e.operand1), " and ", typeName(e.operand2), "\n"); let w = 2; let j = i; while (j /= 10 >= 0) { w += 1 }; for (i from len(e) - 1 to 0) print(pad(w, codeString(i)), ": ", codeString(e[i]), "\n") }

+ 46
- 2
test.txt Visa fil

@ -92,6 +92,7 @@ nfib(n) { if (n < 2) 1 else nfib(n-1) + nfib(n-2) + 1 }
print(nfib(5), "\n");
print(nfib(15), "\n");
/*
assert(x) {
if (!(eval(x))) {
print("\nassertion failed: ", codeString(x), "\n");
@ -100,6 +101,14 @@ assert(x) {
}
assert.fixed = #t; // do not evaluate arguments (x will be an AST suitable for eval())
*/
Symbol.macros.assert = (x) {
`{if (!(eval(@x))) {
print("\nassertion failed: ", @codeString(x), "\n");
exit(1);
}};
};
refute(x) {
if (eval(x)) {
@ -369,12 +378,47 @@ ast = (`6 * @myNode;); // user-defined node in AST
print("AST eval => ", eval(ast), "\n");
print("String to int conversion\n");
print("11111111".asInteger(2), "\n");
print("377".asInteger(8), "\n");
print("255".asInteger(), "\n");
print("FF".asInteger(16), "\n");
for (i from 0 to 10) print(i, " "); print("\n");
for (i from 10 to 0) print(i, " "); print("\n");
for (i in 10) print(i, " "); print("\n");
for (i in "ABCDE") print(i, " "); print("\n");
for (i in [1, "two", 3, "four"]) print(i, " "); print("\n");
factorial(n) { if (n < 2) "1" else n * factorial(n-1) }
factorial(n) { if (n < 2) nil else n * factorial(n-1) }
typeName(x) {
if (!x) return "<Undefined>";
let name = "?";
let level = 1;
while (x && !x.allKeys().includes(#__name__)) x = x.__delegate__;
if (x.allKeys().includes(#__name__)) name = x.__name__.asString();
"<" * level + name + ">" * level;
}
factorial(5);
pad(w, i) {
while (len(i) < w) i = " " + i;
i;
}
try {
factorial(5);
}
catch (e) {
assert(e.__function__ == "*");
assert(e.__kind__ == "type error");
assert(e.__message__ == "illegal operand types");
assert(e.operand1 == 2);
assert(e.operand2 == nil);
print(e.__function__, ": ", e.__kind__, ": ", e.__message__, ": ", typeName(e.operand1), " and ", typeName(e.operand2), "\n");
let w = 2;
let j = i;
while ( (j /= 10) > 0) { ++w; }
for (i from len(e) - 1 to 0)
print(pad(w, codeString(i)), ": ", codeString(e[i]), "\n");
}

Laddar…
Avbryt
Spara