diff --git a/examples/arrow.noja b/examples/arrow.noja index 8664788..5600cfd 100644 --- a/examples/arrow.noja +++ b/examples/arrow.noja @@ -1,5 +1,4 @@ - fun sayHello(self, other) print("Hello ", other, " from ", self.name); diff --git a/examples/http.noja b/examples/http.noja index d1df0d2..4628aa4 100644 --- a/examples/http.noja +++ b/examples/http.noja @@ -3,11 +3,7 @@ scan = import("scan.noja"); newScanner = scan.newScanner; Scanner = scan.Scanner; -hint = scan.hint; -consume = scan.consume; -current = scan.current; isDigit = scan.isDigit; -consumeSpaces = scan.consumeSpaces; ord = string.ord; cat = string.cat; @@ -43,15 +39,15 @@ fun isPChar(char: String) fun parseMethod(scan: Scanner) { - char = current(scan); + char = scan->current(); if char == none or not isUpper(char): return none, "Missing method"; method = ""; do { method = cat(method, char); - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } while char != none and isUpper(char); return method, none; @@ -60,19 +56,19 @@ fun parseMethod(scan: Scanner) { fun parsePort(scan: Scanner) { port = none; - char = current(scan); - if char == ":" and isDigit(hint(scan, 1)): { + char = scan->current(); + if char == ":" and isDigit(scan->hint(1)): { - consume(scan); # Skip the ":" - char = current(scan); + scan->consume(); # Skip the ":" + char = scan->current(); port = 0; do { digit = ord(char) - ord("0"); port = port * 10 + digit; - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } while char != none and isDigit(char); } return port; @@ -84,7 +80,7 @@ fun isHostname(char: String) fun parseHost(scan: Scanner) { - char = current(scan); + char = scan->current(); if char == none: return none, "Missing host"; @@ -94,8 +90,8 @@ fun parseHost(scan: Scanner) { name = ""; do { name = cat(name, char); - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } while char != none and isHostname(char); port = parsePort(scan); @@ -105,11 +101,11 @@ fun parseHost(scan: Scanner) { fun parsePath(scan: Scanner) { path = ""; - char = current(scan); + char = scan->current(); if char != none and char == "/": { path = cat(path, char); - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } else { if char == none or not isPChar(char): return none, "Invalid character in place of path"; @@ -118,14 +114,14 @@ fun parsePath(scan: Scanner) { while char != none and isPChar(char): { do { path = cat(path, char); - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } while char != none and isPChar(char); if char == none or char != "/": break; path = cat(path, char); - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } return path; @@ -141,13 +137,13 @@ fun isQuery(char: ?String) { fun parseQuery(scan: Scanner) { - char = current(scan); + char = scan->current(); if char != none and char == "?": { - consume(scan); # Consume the "?" + scan->consume(); # Consume the "?" query = ""; - while isQuery(char = current(scan)): { + while isQuery(char = scan->current()): { query = cat(query, char); - consume(scan); + scan->consume(); } } else query = none; @@ -163,13 +159,13 @@ fun isFragment(char: ?String) { fun parseFragment(scan: Scanner) { - char = current(scan); + char = scan->current(); if char != none and char == "#": { - consume(scan); # Consume the "#" + scan->consume(); # Consume the "#" fragment = ""; - while isFragment(char = current(scan)): { + while isFragment(char = scan->current()): { fragment = cat(fragment, char); - consume(scan); + scan->consume(); } } else fragment = none; @@ -204,19 +200,19 @@ fun isSchema(char: ?String) fun parseSchema(scan: Scanner) { - char = current(scan); + char = scan->current(); schema = none; if isSchemaFirst(char): { start = scan.i; schema = ""; do { schema = cat(schema, char); - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } while isSchema(char); if char == ":": - consume(scan); + scan->consume(); else { schema = none; scan.i = start; @@ -227,7 +223,7 @@ fun parseSchema(scan: Scanner) { } fun followsAuthority(scan: Scanner) - return current(scan) == "/" and hint(scan, 1) == "/"; + return scan->current() == "/" and scan->hint(1) == "/"; fun parseURL(scan: Scanner) { @@ -241,14 +237,14 @@ fun parseURL(scan: Scanner) { return none, error; path = none; - if current(scan) == "/": + if scan->current() == "/": path = parsePath(scan); } else { host = none; - char = current(scan); + char = scan->current(); if char == none or char == "?" or char == "#": return none, "Missing path"; @@ -271,22 +267,22 @@ fun parseURL(scan: Scanner) { fun parseVersion(scan: Scanner) { - if hint(scan, 0) != "H" or hint(scan, 1) != "T" - or hint(scan, 2) != "T" or hint(scan, 3) != "P" - or hint(scan, 4) != "/" or not isDigit(hint(scan, 5)): + if scan->hint(0) != "H" or scan->hint(1) != "T" + or scan->hint(2) != "T" or scan->hint(3) != "P" + or scan->hint(4) != "/" or not isDigit(scan->hint(5)): return none, "Invalid version token"; - consume(scan, 5); - major = ord(current(scan)) + scan->consume(5); + major = ord(scan->current()) - ord("0"); - if hint(scan, 1) != "." and isDigit(hint(scan, 2)): { - consume(scan, 2); - minor = ord(current(scan)) + if scan->hint(1) != "." and isDigit(scan->hint(2)): { + scan->consume(2); + minor = ord(scan->current()) - ord("0"); } else minor = 0; - consume(scan); + scan->consume(); return {major: major, minor: minor}; } @@ -319,59 +315,59 @@ fun parse(src: String) { if error != none: return none, error; - char = current(scan); + char = scan->current(); if char == none or char != " ": return none, "Missing space after method"; - consume(scan); + scan->consume(); url, error = parseURL(scan); if error != none: return none, error; - char = current(scan); + char = scan->current(); if char != " ": return none, "Missing space after URL"; - consume(scan); + scan->consume(); version, error = parseVersion(scan); if error != none: return none, error; - if hint(scan, 0) != "\r" or hint(scan, 1) != "\n": + if scan->hint(0) != "\r" or scan->hint(1) != "\n": # Request with no headers or body return newRequest(method, url, version); - consume(scan, 2); # Consume the "\r\n" + scan->consume(2); # Consume the "\r\n" headers = {}; - while (char = hint(scan, 0)) != none and (char != "\r" or hint(scan, 1) != "\n"): { + while (char = scan->hint(0)) != none and (char != "\r" or scan->hint(1) != "\n"): { # Header name until the next ":" name = ""; do { name = cat(name, char); - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } while char != ":" and char != none; if char == none: return none, "Invalid header (missing \":\" after name)"; - consume(scan); - consumeSpaces(scan); - char = current(scan); + scan->consume(); + scan->consumeSpaces(); + char = scan->current(); # Header body until \r body = ""; do { body = cat(body, char); - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } while char != "\r" and char != none; headers[name] = body; } if char != none: - consume(scan, 2); # Consume the final "\r\n" + scan->consume(2); # Consume the final "\r\n" return newRequest(method, url, version, headers); } diff --git a/examples/json.noja b/examples/json.noja index b5cd5e5..4427259 100644 --- a/examples/json.noja +++ b/examples/json.noja @@ -2,23 +2,19 @@ scan = import("scan.noja"); newScanner = scan.newScanner; Scanner = scan.Scanner; -hint = scan.hint; -consume = scan.consume; -current = scan.current; -consumeSpaces = scan.consumeSpaces; isDigit = scan.isDigit; fun parseString(scan: Scanner) { - assert(current(scan) == '"'); - consume(scan); # Consume the opening " + assert(scan->current() == '"'); + scan->consume(); # Consume the opening " temp = ""; - char = current(scan); + char = scan->current(); while char != '"' and char != none: { temp = string.cat(temp, char); - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } if char == none: { @@ -26,7 +22,7 @@ fun parseString(scan: Scanner) { err = "Source ended inside a string literal"; } else { assert(char == '"'); - consume(scan); + scan->consume(); val = temp; err = none; } @@ -36,22 +32,22 @@ fun parseString(scan: Scanner) { fun parseObject(scan: Scanner) { - assert(current(scan) == '{'); - consume(scan); + assert(scan->current() == '{'); + scan->consume(); obj = {}; - consumeSpaces(scan); - if current(scan) != '}': do { + scan->consumeSpaces(); + if scan->current() != '}': do { key, err = parseValue(scan); if err != none: return none, err; if type(key) != String: return none, "Object key isn't a string"; - consumeSpaces(scan); - if current(scan) != ':': + scan->consumeSpaces(); + if scan->current() != ':': return none, "Missing ':' separator after key"; - consume(scan); + scan->consume(); val, err = parseValue(scan); if err != none: @@ -61,111 +57,111 @@ fun parseObject(scan: Scanner) { return none, "Duplicate key in object"; obj[key] = val; - consumeSpaces(scan); - if current(scan) == '}': + scan->consumeSpaces(); + if scan->current() == '}': done = true; else { - if current(scan) != ',': + if scan->current() != ',': return none, "Invalid character where either ',' or '}' were expected"; - consume(scan); # Consume the "," + scan->consume(); # Consume the "," done = false; } } while not done; - assert(current(scan) == '}'); - consume(scan); + assert(scan->current() == '}'); + scan->consume(); return obj; } fun parseArray(scan: Scanner) { - assert(current(scan) == '['); - consume(scan); # Consume the [ + assert(scan->current() == '['); + scan->consume(); # Consume the [ array = []; - consumeSpaces(scan); - if current(scan) != ']': do { + scan->consumeSpaces(); + if scan->current() != ']': do { val, err = parseValue(scan); if err != none: return none, err; array[count(array)] = val; - consumeSpaces(scan); - if current(scan) == ']': + scan->consumeSpaces(); + if scan->current() == ']': done = true; else { - if current(scan) != ',': + if scan->current() != ',': return none, "Invalid character where either ',' or ']' were expected"; - consume(scan); # Consume the "," + scan->consume(); # Consume the "," done = false; } } while not done; - assert(current(scan) == ']'); - consume(scan); + assert(scan->current() == ']'); + scan->consume(); return array; } fun parseFalse(scan: Scanner) { - assert(current(scan) == 'f'); - consume(scan); + assert(scan->current() == 'f'); + scan->consume(); - if current(scan) != 'a': + if scan->current() != 'a': return none, "Invalid character after 'f'"; - consume(scan); + scan->consume(); - if current(scan) != 'l': + if scan->current() != 'l': return none, "Invalid character after 'fa'"; - consume(scan); + scan->consume(); - if current(scan) != 's': + if scan->current() != 's': return none, "Invalid character after 'fal'"; - consume(scan); + scan->consume(); - if current(scan) != 'e': + if scan->current() != 'e': return none, "Invalid character after 'fals'"; - consume(scan); + scan->consume(); return false; } fun parseTrue(scan: Scanner) { - assert(current(scan) == 't'); - consume(scan); + assert(scan->current() == 't'); + scan->consume(); - if current(scan) != 'r': + if scan->current() != 'r': return none, "Invalid character after 't'"; - consume(scan); + scan->consume(); - if current(scan) != 'u': + if scan->current() != 'u': return none, "Invalid character after 'tr'"; - consume(scan); + scan->consume(); - if current(scan) != 'e': + if scan->current() != 'e': return none, "Invalid character after 'tru'"; - consume(scan); + scan->consume(); return true; } fun parseNull(scan: Scanner) { - assert(current(scan) == 'n'); - consume(scan); + assert(scan->current() == 'n'); + scan->consume(); - if current(scan) != 'u': + if scan->current() != 'u': return none, "Invalid character after 'n'"; - consume(scan); + scan->consume(); - if current(scan) != 'l': + if scan->current() != 'l': return none, "Invalid character after 'nu'"; - consume(scan); + scan->consume(); - if current(scan) != 'l': + if scan->current() != 'l': return none, "Invalid character after 'nul'"; - consume(scan); + scan->consume(); return none; } @@ -178,15 +174,15 @@ fun integerFromDigit(char: String) { fun parseNumber(scan: Scanner) { - char = current(scan); + char = scan->current(); sign = 1; if char == '+' or char == '-': { sign = {'+': 1, '-': -1}[char]; - consume(scan); + scan->consume(); - char = current(scan); + char = scan->current(); if not isDigit(char): return none, "Invalid character after +/-"; } @@ -198,23 +194,23 @@ fun parseNumber(scan: Scanner) { n = integerFromDigit(char); temp = temp * 10 + n; - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } while isDigit(char); - if char == '.' and isDigit(hint(scan, 1)): { + if char == '.' and isDigit(scan->hint(1)): { - consume(scan); # Consume the dot - char = current(scan); + scan->consume(); # Consume the dot + char = scan->current(); q = 1.0; do { q = q / 10; n = integerFromDigit(char); temp = temp + q * n; - consume(scan); - char = current(scan); + scan->consume(); + char = scan->current(); } while isDigit(char); } @@ -244,8 +240,8 @@ fun parseValue(scan: Scanner) { '9': parseNumber }; - consumeSpaces(scan); - char = current(scan); + scan->consumeSpaces(); + char = scan->current(); if char == none: { val = none; err = "Source ended where a value was expected"; diff --git a/examples/scan.noja b/examples/scan.noja index 90b5b24..2b6b417 100644 --- a/examples/scan.noja +++ b/examples/scan.noja @@ -1,8 +1,46 @@ -Scanner = {src: String, i: int}; +fun dummy() {} +Func = type(dummy) + | type(print); + +Scanner = { + src: String, + i: int, + hint: Func, + current: Func, + consume: Func, + consumeSpaces: Func +}; + +fun hint(scan: Scanner, n: int = 1) { + k = scan.i + n; + if k < count(scan.src): + return scan.src[k]; + return none; +} + +fun current(scan: Scanner) + return hint(scan, 0); + +fun consume(scan: Scanner, n: int = 1) { + assert(n > 0); + limit = count(scan.src); + scan.i = min(scan.i + n, limit); +} + +fun consumeSpaces(scan: Scanner) + while isSpace(current(scan)): + consume(scan); fun newScanner(src: String) { - scan = {src: src, i: 0}; + scan = { + src: src, + i: 0, + hint: hint, + consume: consume, + current: current, + consumeSpaces: consumeSpaces + }; assert(istypeof(Scanner, scan)); return scan; } @@ -23,24 +61,4 @@ fun min(x, y) { if x < y: return x; return y; -} - -fun hint(scan: Scanner, n: int = 1) { - k = scan.i + n; - if k < count(scan.src): - return scan.src[k]; - return none; -} - -fun current(scan: Scanner) - return hint(scan, 0); - -fun consume(scan: Scanner, n: int = 1) { - assert(n > 0); - limit = count(scan.src); - scan.i = min(scan.i + n, limit); -} - -fun consumeSpaces(scan: Scanner) - while isSpace(current(scan)): - consume(scan); \ No newline at end of file +} \ No newline at end of file