diff options
Diffstat (limited to 'internal/parser')
| -rw-r--r-- | internal/parser/.parser.ha.swp | bin | 20480 -> 0 bytes | |||
| -rw-r--r-- | internal/parser/parser.ha | 123 |
2 files changed, 116 insertions, 7 deletions
diff --git a/internal/parser/.parser.ha.swp b/internal/parser/.parser.ha.swp Binary files differdeleted file mode 100644 index e2d9062..0000000 --- a/internal/parser/.parser.ha.swp +++ /dev/null diff --git a/internal/parser/parser.ha b/internal/parser/parser.ha index 682cb35..39b9abc 100644 --- a/internal/parser/parser.ha +++ b/internal/parser/parser.ha @@ -12,8 +12,9 @@ use fmt; // value: str, //}; -export type token = (varname | assign | operation); +export type token = (varname | finvoke | assign | operation | arglist); +export type finvoke = rune; export type assign = rune; export type varname = str; @@ -29,14 +30,18 @@ export type operation = struct { stack: []argument, }; +export type arglist = []str; + export type tokentype = enum { START, VARNAME, + FINVOKE, OPERAND, OPERATOR, OPERATION, LITERAL, ASSIGN, + ARGLIST, }; export type parseerror = !(size, size, str); @@ -46,11 +51,13 @@ export type error = !(parseerror | io::error | utf8::invalid | strconv::invalid export fn strtktype(tktype: tokentype) str = switch (tktype) { case tokentype::START => yield "START"; case tokentype::VARNAME => yield "VARNAME"; +case tokentype::FINVOKE => yield "FINVOKE"; case tokentype::OPERAND => yield "OPERAND"; case tokentype::OPERATOR => yield "OPERATOR"; case tokentype::OPERATION => yield "OPERATION"; case tokentype::LITERAL => yield "LITERAL"; case tokentype::ASSIGN => yield "ASSIGN"; +case tokentype::ARGLIST => yield "ARGLIST"; }; //export fn parseast(h: io::handle) (void | io::error) = { @@ -64,6 +71,14 @@ export type parser = struct { unreadcount: size, }; +type validrunecondfn = *fn(c: rune) bool; + +type validrunecond = struct { + f: validrunecondfn, + err: const str, +}; + + export fn strerror(e: error) str = { static let b: [256]u8 = @undefined; return match (e) { @@ -94,13 +109,62 @@ fn read_rune(p: *parser) (rune | io::EOF | error) = { }; }; +fn runeisin(r: rune, rs: []rune) bool = { + for (let i = 0z; i < len(rs); i += 1) { + if (r == rs[i]) { + return true; + }; + } else { + return false; + }; +}; + +fn parsetil( + p: *parser, + til: (rune | []rune), + cond: (void | validrunecond), + runecount: size, + linenb: size = 0, +) +(str | error) = { + let m = memio::dynamic(); + defer io::close(&m)!; + + return for (let r => read_rune(p)?) { + runecount += 1; + const ismatch = match (til) { + case let ru: rune => + yield r == ru; + case let ru: []rune => + yield runeisin(r, ru); + }; + if (ismatch) { + unreadrune(p, r); + let s = strings::trim(memio::string(&m)?); + break strings::dup(s)?; + }; + match (cond) { + case void => + memio::appendrune(&m, r)?; + case let c: validrunecond => + if (c.f(r)) { + memio::appendrune(&m, r)?; + } else { + break (runecount, linenb, c.err): error; + }; + }; + } else { + return (runecount, linenb, "Syntax error: variable not assigned or used"): error; + }; +}; + fn parsevarname(p: *parser, runecount: size, linenb: size = 0) (varname | error) = { let m = memio::dynamic(); defer io::close(&m)!; return for (let r => read_rune(p)?) { runecount += 1; - if (r == '=') { + if (r == '=' || r == '(') { unreadrune(p, r); let s = strings::trim(memio::string(&m)?); break strings::dup(s)?: varname; @@ -115,6 +179,36 @@ fn parsevarname(p: *parser, runecount: size, linenb: size = 0) (varname | error) }; }; +fn parsearglist(p: *parser, runecount: size, linenb: size = 0) (arglist | error) = { + static let buf: [256]u8 = @undefined; + let arglist: arglist = []; + + let m = memio::dynamic(); + defer io::close(&m)!; + + for (let r => read_rune(p)?) { + switch (r) { + case '"' => + let arg = parsetil(p, '"', void, 0z)?; + // reread unread " + read_rune(p)?; + append(arglist, arg)?; + case '\'' => + let arg = parsetil(p, '\'', void, 0z)?; + // reread unread ' + read_rune(p)?; + append(arglist, arg)?; + case ',', ' ' => + continue; + case ')' => + break; + case => + return (runecount, linenb, "Argument literals must be wrapped with \" or '"): error; + }; + }; + return arglist; +}; + fn parseoperation(p: *parser, runecount: size, linenb: size = 0) (operation | error) = { static let buf: [256]u8 = @undefined; let stack: []argument = []; @@ -214,9 +308,9 @@ export fn parse(p: *parser, linenb: size = 0) (ast | error) = { children = [], }; append(tree, node)?; - case assign => + case (assign | finvoke) => root.value = t; - case operation => + case (operation | arglist) => let node: ast = ast { value = t, children = [], @@ -229,6 +323,8 @@ export fn parse(p: *parser, linenb: size = 0) (ast | error) = { return root; }; +fn isalnum(c: rune) bool = ascii::isalnum(c); + export fn parsetoken(p: *parser, linenb: size = 0) (token | error) = { static let buf: [256]u8 = @undefined; let runecount = 0z; @@ -236,7 +332,12 @@ export fn parsetoken(p: *parser, linenb: size = 0) (token | error) = { return switch (p.state) { case tokentype::START => // VARNAME - let t = parsevarname(p, 0z)?; + //let t = parsevarname(p, 0z)?; + const cond = validrunecond { + f = &isalnum: validrunecondfn, + err = "Character is not alphanumeric", + }; + let t = parsetil(p, ['=', '('], cond, 0z)?; p.state = tokentype::VARNAME; yield t; case tokentype::VARNAME => @@ -246,14 +347,22 @@ export fn parsetoken(p: *parser, linenb: size = 0) (token | error) = { case let r: rune => yield if (r == '=') { p.state = tokentype::ASSIGN; - yield '='; + yield '=': assign; + } else if (r == '(') { + p.state = tokentype::FINVOKE; + yield '(': finvoke; } else { - const msg = fmt::bsprintf(buf, "Missing '=', found '{}' instead", r)?; + const msg = fmt::bsprintf(buf, "Missing '=' or '(', found '{}' instead", r)?; yield (runecount, linenb, msg): error; }; case io::EOF => yield (runecount, linenb, "Unexpected EOF"): error; }; + case tokentype::FINVOKE => + // look for FINVOKE + let t = parsearglist(p, 0z)?; + p.state = tokentype::START; + yield t; case tokentype::ASSIGN => // look for OPERATION let t = parseoperation(p, 0z)?; |
