19 Коміти

Автор SHA1 Повідомлення Дата
  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. 11 місяці тому
  MaximeBarniaudy 1e73ce0d16 Make grammar_parser.meta use the entire grammar from minproto.leg 11 місяці тому
  MaximeBarniaudy 0a6802237f Add optional base argument to String.asInteger 11 місяці тому
  MaximeBarniaudy e482c081a9 Fix error after single quote semantics change 11 місяці тому
  MaximeBarniaudy 45686c7730 Add with and without functions for namespace manimulation, add namespace support to grammars, add test of parser circularity 1 рік тому
  MaximeBarniaudy 23be24b142 parser circularity 1 рік тому
  MaximeBarniaudy 4b1752f399 dotdot got lost in merging 1 рік тому
  MaximeBarniaudy 35fa3e9158 Add Invoke and GetProp 1 рік тому
  MaximeBarniaudy be4e0b8322 Minimal grammar parsing 1 рік тому
  MaximeBarniaudy 7b914a509c Add an intern primitive for symbol creation 1 рік тому
  MaximeBarniaudy 6de35d8a4a Fix range access overshadowing key access 1 рік тому
  WitherFlower dbc8265409 Merge range access and grammar parser changes 1 рік тому
  Ian Piumarta 2171f47dce Fold constants during parsing if FOLDCONST=1. 11 місяці тому
  Ian Piumarta 4d396d6170 Fix floating point comparison and assignment operators. 11 місяці тому
  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. 11 місяці тому
  Ian Piumarta ea60878c24 Add exception tests. New test.txt reference output. 11 місяці тому
  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(). 11 місяці тому
  Ian Piumarta 207ef22fb0 Upate test reference output. 11 місяці тому
  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. 11 місяці тому
7 змінених файлів з 2397 додано та 260 видалено
  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
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 805
- 244
minproto.leg
Різницю між файлами не показано, бо вона завелика
Переглянути файл


+ 73
- 0
rawMetaGrammar.leg Переглянути файл

@ -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 Переглянути файл

@ -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 Переглянути файл

@ -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 Переглянути файл

@ -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 Переглянути файл

@ -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");
}

Завантаження…
Відмінити
Зберегти