From 17c2e241a2c83d10cc5579857476df57fc358bb1 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Wed, 7 Jun 2023 09:46:05 +1000 Subject: [PATCH 01/19] Handle string escapes properly; handle exponents --- samples/json.wybe | 251 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 samples/json.wybe diff --git a/samples/json.wybe b/samples/json.wybe new file mode 100644 index 00000000..cd016def --- /dev/null +++ b/samples/json.wybe @@ -0,0 +1,251 @@ +pub constructors jobject(list(pair)) | jstring(string) | jbool(bool) | jnumber(float) | jlist(list(_)) | jnull + +pub def {test} (a:_ = b:_) { fail } + +pub type pair { + pub pair(key:string, value:json) + + pub def {test} (a:_ = b:_) { fail } +} + +pub def {test} parse(s:string, ?json:_) { + space(!s) + json(!s, ?json) +} + +def {test} char(c:char, !s:string) { + # this is necessary because the uncons may fail, but the failure overwrites s + # [c | ?s] = s + [c | ?s_] = s + ?s = s_ +} + +def {test} string(str:string, !s:string) { + for ?c in str { + char(c, !s) + } + space(!s) +} + +def space(!s:string) { + if { { char(' ', !s) | char('\n', !s) | char('\r', !s) | char('\t', !s) } :: space(!s) } +} + +def {test} json(!s:string, ?j:_) { + object(!s, ?j) + | string(!s, ?str) & ?j = jstring(str) + | bool(!s, ?j) + | number(!s, ?j) + | list(!s, ?j) + | null(!s) & ?j = jnull +} + +# this should work... +# I think the xs is not being passed out +# def {test} list_like(before:char, parse:{test}(!string, ?X), !s:string, ?xs:list(X), after:char) { +# char(before, !s) +# if { parse(!s, ?x) :: +# list_tail(parse, !s, ?xs) +# ?xs = [x | xs] +# | else :: +# ?xs = [] +# } +# space(!s) +# char(after, !s) +# space(!s) +# } + +def {test} list_like(before:char, parse:{test}(!string, ?X), !s:string, ?xs:list(X), after:char) { + char(before, !s) + space(!s) + list_like(parse, !s, ?xs) + space(!s) + char(after, !s) + space(!s) +} +def {test} list_like(parse:{test}(!string, ?X), !s:string, ?xs:list(X)) { + if { parse(!s, ?x) :: + list_tail(parse, !s, ?xs) + ?xs = [x | xs] + | else :: + ?xs = [] + } +} + +def {test} list_tail(parse:{test}(!string, ?X), !s:string, ?xs:list(X)) { + if { char(',', !s) :: + space(!s) + parse(!s, ?x) + list_tail(parse, !s, ?xs) + ?xs = [x | xs] + | else :: + ?xs = [] + } +} + +def {test} object(!s:string, ?obj:_) { + list_like('{', pair, !s, ?ps, '}') + ?obj = jobject(ps) +} + +def {test} pair(!s:string, ?pair:pair) { + string(!s, ?key) + space(!s) + char(':', !s) + space(!s) + json(!s, ?value) + space(!s) + ?pair = pair(key, value) +} + +def {test} string(!s:string, ?str:string) { + char('\"', !s) + string_(!s, ?str) + ?str = string(c_string(str)) +} + +def {test} string_(!s:string, ?str:string) { + char('\"', !s) + ?str = "" + space(!s) + | [?c | ?s] = s + if { c = '\\' :: + [?c | ?s] = s + if { c = '"' :: pass + | c = '\\' :: pass + | c = '/' :: pass + | c = 'b' :: ?c = '\b' + | c = 'f' :: ?c = '\f' + | c = 'n' :: ?c = '\n' + | c = 'r' :: ?c = '\r' + | c = 't' :: ?c = '\t' + | else :: fail + } + } + string_(!s, ?str) + ?str = [c | str] +} + +def {test} bool(!s:string, ?bool:_) { + string("false", !s) + ?bool = jbool(false) + | string("true", !s) + ?bool = jbool(true) +} + +def {test} number(!s:string, ?number:_) { + digit(!s, ?n) + digits(!s, _, !n) + if { char('.', !s) :: + digit(!s, ?f) + digits(!s, ?len, !f) + !n += f / power(10.0, len) + } + if { { char('e', !s) | char('E', !s) } :: + digit(!s, ?e) + digits(!s, _, !e) + !n *= power(10.0, e) + } + space(!s) + ?number = jnumber(n) +} + +def {test} digits(!s:string, ?len:float, !n:float) { + digit(!s, ?d) + ?n = n * 10.0 + d + digits(!s, ?len, !n) + !len += 1.0 + | ?len = 1.0 +} + +def {test} digit(!s:string, ?d:float) { + [?c | ?rest] = s + '0' <= c & c <= '9' + ?s = rest + ?d = float(ord(c) - ord('0')) +} + +def {test} list(!s:string, ?list:_) { + list_like('[', json, !s, ?js, ']') + ?list = jlist(js) +} + +def {test} null(!s:string) { + string("null", !s) +} + +pub def print(x:_) use !io { + !print(0, x) + !nl +} + +def print(ind:int, p:pair) use !io { + !indent(ind) + !escape(p^key) + !print(": ") + !print(ind + 1, p^value) +} + +def escape(s:string) use !io { + !print('"') + for ?c in s { + if { c = '"' :: !print("\\\"") + | c = '\\' :: !print("\\\\") + | c = '\b' :: !print("\\b") + | c = '\f' :: !print("\\f") + | c = '\n' :: !print("\\n") + | c = '\r' :: !print("\\r") + | c = '\t' :: !print("\\t") + | else :: !print(c) + } + } + !print('"') +} + +def print_list(start:char, printer:{resource}(int, X), ind:int, xs:list(X), end:char) use !io { + !print(start) + if { [?x | ?xs] = xs :: + !nl + !printer(ind + 1, x) + for ?x in xs { + !println(',') + !printer(ind + 1, x) + } + !nl + !indent(ind) + } + !print(end) +} + +def print(ind:int, x:_) use !io { + case x in { + jobject(?pairs) :: + !print_list('{', print, ind, pairs, '}') + | jlist(?list) :: + !print_list('[', {resource}{ + !indent(@1) + !print(@1, @2) + }, ind, list, ']') + | jstring(?s) :: + !escape(s) + | jbool(?b) :: + !print(b) + | jnumber(?n) :: + !print(n) + | else :: + !print("null") + } +} + +def indent(ind:int) use !io { + for _ in 0..ind { + !print(" ") + } +} + +?s = "{\"ab\\nc\" : [false, true, 123.098, 123, 123.456e10], \"def\": null}" +if { parse(!s, ?j) :: + !print(j) + | else :: + !error("failed to parse") +} \ No newline at end of file From 912b11d6878b33f8460f3e89b6d4f57cef977087 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Mon, 19 Jun 2023 13:34:39 +1000 Subject: [PATCH 02/19] Refined JSON example with documentation and name improvements --- samples/json.wybe | 131 ++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 57 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index cd016def..7b886128 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -1,18 +1,24 @@ pub constructors jobject(list(pair)) | jstring(string) | jbool(bool) | jnumber(float) | jlist(list(_)) | jnull -pub def {test} (a:_ = b:_) { fail } +pub def {test} (a:_ = b:_) { foreign lpvm cast(a):int = foreign lpvm cast(b):int } pub type pair { + ## pair type + # A pair contianing a key and value. pub pair(key:string, value:json) - - pub def {test} (a:_ = b:_) { fail } } +## parse/2 +# Parse a string into a JSON value. +# Fails if the string cannot be parsed. pub def {test} parse(s:string, ?json:_) { space(!s) json(!s, ?json) } +## char/2 +# Parse a single character from the input string. +# Fails if the first character of the string is not said character. def {test} char(c:char, !s:string) { # this is necessary because the uncons may fail, but the failure overwrites s # [c | ?s] = s @@ -20,17 +26,33 @@ def {test} char(c:char, !s:string) { ?s = s_ } -def {test} string(str:string, !s:string) { + +## space/1 +# Parse zero or more whitespace characters from the input. +def space(!s:string) { + if { { char(' ', !s) | char('\n', !s) | char('\r', !s) | char('\t', !s) } :: + space(!s) + } +} + +## char_token/2 +# Parse a character followed by whitespace. +def {test} char_token(c:char, !s:string) { + char(c, !s) + space(!s) +} + +## string_token/2 +# Parse a string literal followed by whitespace. +def {test} string_token(str:string, !s:string) { for ?c in str { char(c, !s) } space(!s) -} - -def space(!s:string) { - if { { char(' ', !s) | char('\n', !s) | char('\r', !s) | char('\t', !s) } :: space(!s) } } +## json/1 +# Parse a JSON object followed by whitespace. def {test} json(!s:string, ?j:_) { object(!s, ?j) | string(!s, ?str) & ?j = jstring(str) @@ -40,74 +62,57 @@ def {test} json(!s:string, ?j:_) { | null(!s) & ?j = jnull } -# this should work... -# I think the xs is not being passed out -# def {test} list_like(before:char, parse:{test}(!string, ?X), !s:string, ?xs:list(X), after:char) { -# char(before, !s) -# if { parse(!s, ?x) :: -# list_tail(parse, !s, ?xs) -# ?xs = [x | xs] -# | else :: -# ?xs = [] -# } -# space(!s) -# char(after, !s) -# space(!s) -# } - -def {test} list_like(before:char, parse:{test}(!string, ?X), !s:string, ?xs:list(X), after:char) { - char(before, !s) - space(!s) - list_like(parse, !s, ?xs) - space(!s) - char(after, !s) - space(!s) -} -def {test} list_like(parse:{test}(!string, ?X), !s:string, ?xs:list(X)) { +## sequence/5 +# Parse a comma-separated sequence of things, with a preceding and +# following character, followed by whitespace. +def {test} sequence(before:char, parse:{test}(!string, ?X), !s:string, ?xs:list(X), after:char) { + char_token(before, !s) if { parse(!s, ?x) :: - list_tail(parse, !s, ?xs) + sequence_tail(parse, !s, ?xs) ?xs = [x | xs] | else :: ?xs = [] } + char_token(after, !s) } -def {test} list_tail(parse:{test}(!string, ?X), !s:string, ?xs:list(X)) { - if { char(',', !s) :: - space(!s) +## sequence_tail/3 +# Parse the tail of a sequnece. Helper for sequence/2. +def {test} sequence_tail(parse:{test}(!string, ?X), !s:string, ?xs:list(X)) { + if { char_token(',', !s) :: parse(!s, ?x) - list_tail(parse, !s, ?xs) + sequence_tail(parse, !s, ?xs) ?xs = [x | xs] | else :: ?xs = [] } } +## object/2 +# Parse a JSON object, followed by whitespace. def {test} object(!s:string, ?obj:_) { - list_like('{', pair, !s, ?ps, '}') + sequence('{', {test}{ + string(!@1, ?key) + char_token(':', !@1) + json(!@1, ?value) + ?@2 = pair(key, value) + }, !s, ?ps, '}') ?obj = jobject(ps) } -def {test} pair(!s:string, ?pair:pair) { - string(!s, ?key) - space(!s) - char(':', !s) - space(!s) - json(!s, ?value) - space(!s) - ?pair = pair(key, value) -} - +## string/2 +# Parse a string, followed by whitespace. def {test} string(!s:string, ?str:string) { char('\"', !s) - string_(!s, ?str) + string_tail(!s, ?str) ?str = string(c_string(str)) } -def {test} string_(!s:string, ?str:string) { - char('\"', !s) +## string_tail/2 +# Parse the tail of a string. Helper for string/2. +def {test} string_tail(!s:string, ?str:string) { + char_token('\"', !s) ?str = "" - space(!s) | [?c | ?s] = s if { c = '\\' :: [?c | ?s] = s @@ -122,17 +127,21 @@ def {test} string_(!s:string, ?str:string) { | else :: fail } } - string_(!s, ?str) + string_tail(!s, ?str) ?str = [c | str] } +## bool/2 +# Parse a JSON Boolean, followed by whitespace. def {test} bool(!s:string, ?bool:_) { - string("false", !s) + string_token("false", !s) ?bool = jbool(false) - | string("true", !s) + | string_token("true", !s) ?bool = jbool(true) } +## number/2 +# Parse a JSON number, followed by whitespace. def {test} number(!s:string, ?number:_) { digit(!s, ?n) digits(!s, _, !n) @@ -150,6 +159,8 @@ def {test} number(!s:string, ?number:_) { ?number = jnumber(n) } +## digits/3 +# Parse a sequence of digits, outputting the number of digits parsed def {test} digits(!s:string, ?len:float, !n:float) { digit(!s, ?d) ?n = n * 10.0 + d @@ -158,6 +169,8 @@ def {test} digits(!s:string, ?len:float, !n:float) { | ?len = 1.0 } +## digits/3 +# Parse a single digit digits def {test} digit(!s:string, ?d:float) { [?c | ?rest] = s '0' <= c & c <= '9' @@ -165,13 +178,17 @@ def {test} digit(!s:string, ?d:float) { ?d = float(ord(c) - ord('0')) } +## list/2 +# Parse a JSON list, followed by whitespace. def {test} list(!s:string, ?list:_) { - list_like('[', json, !s, ?js, ']') + sequence('[', json, !s, ?js, ']') ?list = jlist(js) } +## null/2 +# Parse a JSON null, followed by whitespace. def {test} null(!s:string) { - string("null", !s) + string_token("null", !s) } pub def print(x:_) use !io { From f6aef33fbd9126c04d61bee5118b8c99f1f90de8 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Mon, 19 Jun 2023 13:37:11 +1000 Subject: [PATCH 03/19] Refined the defintion of space --- samples/json.wybe | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 7b886128..6ec00f45 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -26,15 +26,6 @@ def {test} char(c:char, !s:string) { ?s = s_ } - -## space/1 -# Parse zero or more whitespace characters from the input. -def space(!s:string) { - if { { char(' ', !s) | char('\n', !s) | char('\r', !s) | char('\t', !s) } :: - space(!s) - } -} - ## char_token/2 # Parse a character followed by whitespace. def {test} char_token(c:char, !s:string) { @@ -42,6 +33,16 @@ def {test} char_token(c:char, !s:string) { space(!s) } +## space/1 +# Parse zero or more whitespace characters from the input. +def space(!s:string) { + char_token(' ', !s) + | char_token('\n', !s) + | char_token('\r', !s) + | char_token('\t', !s) + | pass +} + ## string_token/2 # Parse a string literal followed by whitespace. def {test} string_token(str:string, !s:string) { From f0da735275a470eae673326a8d031ed5d1c5a066 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Tue, 21 Nov 2023 11:54:28 +1100 Subject: [PATCH 04/19] uplift PR with new changes --- samples/json.wybe | 80 ++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 6ec00f45..4b7db94c 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -1,4 +1,11 @@ -pub constructors jobject(list(pair)) | jstring(string) | jbool(bool) | jnumber(float) | jlist(list(_)) | jnull +use wybe.float + +pub constructors jobject(list(pair)) + | jstring(string) + | jbool(bool) + | jnumber(float) + | jlist(list(_)) + | jnull pub def {test} (a:_ = b:_) { foreign lpvm cast(a):int = foreign lpvm cast(b):int } @@ -21,6 +28,7 @@ pub def {test} parse(s:string, ?json:_) { # Fails if the first character of the string is not said character. def {test} char(c:char, !s:string) { # this is necessary because the uncons may fail, but the failure overwrites s + # this still doesnt work # [c | ?s] = s [c | ?s_] = s ?s = s_ @@ -115,7 +123,7 @@ def {test} string_tail(!s:string, ?str:string) { char_token('\"', !s) ?str = "" | [?c | ?s] = s - if { c = '\\' :: + if { c:char = '\\' :: [?c | ?s] = s if { c = '"' :: pass | c = '\\' :: pass @@ -128,8 +136,10 @@ def {test} string_tail(!s:string, ?str:string) { | else :: fail } } - string_tail(!s, ?str) - ?str = [c | str] + string_tail(!s, ?str:string) + # this should work... + # ?str = [c | str] + ?str = string(c) ,, str } ## bool/2 @@ -176,7 +186,7 @@ def {test} digit(!s:string, ?d:float) { [?c | ?rest] = s '0' <= c & c <= '9' ?s = rest - ?d = float(ord(c) - ord('0')) + ?d = foreign llvm sitofp(ord(c) - ord('0')) } ## list/2 @@ -197,11 +207,35 @@ pub def print(x:_) use !io { !nl } -def print(ind:int, p:pair) use !io { - !indent(ind) - !escape(p^key) - !print(": ") - !print(ind + 1, p^value) +def print(ind:int, x:_) use !io { + case x in { + jobject(?pairs) :: + !print_list('{', {resource}{ + !indent(@1) + !escape(@2^key) + !print(": ") + !print(@1 + 1, @2^value) + }, ind, pairs, '}') + | jlist(?list) :: + !print_list('[', {resource}{ + !indent(@1) + !print(@1, @2) + }, ind, list, ']') + | jstring(?s) :: + !escape(s) + | jbool(?b) :: + !print(b) + | jnumber(?n) :: + !print(n) + | else :: + !print("null") + } +} + +def indent(ind:int) use !io { + for _ in 0..ind { + !print(" ") + } } def escape(s:string) use !io { @@ -235,32 +269,6 @@ def print_list(start:char, printer:{resource}(int, X), ind:int, xs:list(X), end: !print(end) } -def print(ind:int, x:_) use !io { - case x in { - jobject(?pairs) :: - !print_list('{', print, ind, pairs, '}') - | jlist(?list) :: - !print_list('[', {resource}{ - !indent(@1) - !print(@1, @2) - }, ind, list, ']') - | jstring(?s) :: - !escape(s) - | jbool(?b) :: - !print(b) - | jnumber(?n) :: - !print(n) - | else :: - !print("null") - } -} - -def indent(ind:int) use !io { - for _ in 0..ind { - !print(" ") - } -} - ?s = "{\"ab\\nc\" : [false, true, 123.098, 123, 123.456e10], \"def\": null}" if { parse(!s, ?j) :: !print(j) From 399b6791948197b4bc15f7dd7b31ff10ab62a3a9 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Sun, 29 Sep 2024 00:28:30 +1000 Subject: [PATCH 05/19] Use a resource in JSON parser sample after various bug fixes --- samples/json.wybe | 199 ++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 102 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 4b7db94c..47850249 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -1,4 +1,5 @@ use wybe.float +use logging pub constructors jobject(list(pair)) | jstring(string) @@ -7,7 +8,9 @@ pub constructors jobject(list(pair)) | jlist(list(_)) | jnull -pub def {test} (a:_ = b:_) { foreign lpvm cast(a):int = foreign lpvm cast(b):int } +pub def {test} (a:_ = b:_) { + foreign lpvm cast(a):int = foreign lpvm cast(b):int +} pub type pair { ## pair type @@ -15,116 +18,112 @@ pub type pair { pub pair(key:string, value:json) } +resource tokens:string + ## parse/2 # Parse a string into a JSON value. # Fails if the string cannot be parsed. -pub def {test} parse(s:string, ?json:_) { - space(!s) - json(!s, ?json) +pub def {test} parse(tokens:string, ?json:_) { + use tokens in { + !space + !json(?json) + } } ## char/2 # Parse a single character from the input string. -# Fails if the first character of the string is not said character. -def {test} char(c:char, !s:string) { - # this is necessary because the uncons may fail, but the failure overwrites s - # this still doesnt work - # [c | ?s] = s - [c | ?s_] = s - ?s = s_ -} - -## char_token/2 -# Parse a character followed by whitespace. -def {test} char_token(c:char, !s:string) { - char(c, !s) - space(!s) +def {test} char(?c:char) use !tokens { + tokens = [?c | ?tokens] } -## space/1 -# Parse zero or more whitespace characters from the input. -def space(!s:string) { - char_token(' ', !s) - | char_token('\n', !s) - | char_token('\r', !s) - | char_token('\t', !s) - | pass +## literal/2 +# Parse a character literal followed by whitespace. +def {test} literal(c:char) use !tokens { + !char(c) + !space } -## string_token/2 +## literal/2 # Parse a string literal followed by whitespace. -def {test} string_token(str:string, !s:string) { +def {test} literal(str:string) use !tokens { for ?c in str { - char(c, !s) + !char(c) } - space(!s) + !space +} + +## space/1 +# Parse zero or more whitespace characters from the input. +def space() use !tokens { + !char(?c) & (c = ' ' | c = '\n' | c = '\r' | c = '\t') + | pass } ## json/1 # Parse a JSON object followed by whitespace. -def {test} json(!s:string, ?j:_) { - object(!s, ?j) - | string(!s, ?str) & ?j = jstring(str) - | bool(!s, ?j) - | number(!s, ?j) - | list(!s, ?j) - | null(!s) & ?j = jnull +def {test} json(?j:_) use !tokens { + !object(?j) + | !string(?str) & ?j = jstring(str) + | !bool(?j) + | !number(?j) + | !list(?j) + | !null & ?j = jnull } ## sequence/5 # Parse a comma-separated sequence of things, with a preceding and # following character, followed by whitespace. -def {test} sequence(before:char, parse:{test}(!string, ?X), !s:string, ?xs:list(X), after:char) { - char_token(before, !s) - if { parse(!s, ?x) :: - sequence_tail(parse, !s, ?xs) +def {test} sequence(before:char, parse:{resource,test}(?X), ?xs:list(X), after:char) use !tokens { + !literal(before) + if { parse(?x) :: + !sequence_tail(parse, ?xs) ?xs = [x | xs] | else :: ?xs = [] } - char_token(after, !s) + !literal(after) } ## sequence_tail/3 # Parse the tail of a sequnece. Helper for sequence/2. -def {test} sequence_tail(parse:{test}(!string, ?X), !s:string, ?xs:list(X)) { - if { char_token(',', !s) :: - parse(!s, ?x) - sequence_tail(parse, !s, ?xs) +def {test} sequence_tail(parse:{resource,test}(?X), ?xs:list(X)) use !tokens { + if { !literal(',') :: + !parse(?x) + !sequence_tail(parse, ?xs) ?xs = [x | xs] - | else :: + | else :: ?xs = [] } } ## object/2 # Parse a JSON object, followed by whitespace. -def {test} object(!s:string, ?obj:_) { - sequence('{', {test}{ - string(!@1, ?key) - char_token(':', !@1) - json(!@1, ?value) - ?@2 = pair(key, value) - }, !s, ?ps, '}') +def {test} object(?obj:_) use !tokens { + !sequence('{', {test,resource}{ + !string(?key) + !literal(':') + !json(?value) + ?@ = pair(key, value) + }, ?ps, '}') ?obj = jobject(ps) } ## string/2 # Parse a string, followed by whitespace. -def {test} string(!s:string, ?str:string) { - char('\"', !s) - string_tail(!s, ?str) +def {test} string(?str:string) use !tokens { + !char('\"') + !string_tail(?str) ?str = string(c_string(str)) } ## string_tail/2 # Parse the tail of a string. Helper for string/2. -def {test} string_tail(!s:string, ?str:string) { - char_token('\"', !s) +def {test} string_tail(?str:string) use !tokens { + !literal('\"') ?str = "" - | [?c | ?s] = s + | !char(?c) if { c:char = '\\' :: - [?c | ?s] = s + !char(?c) if { c = '"' :: pass | c = '\\' :: pass | c = '/' :: pass @@ -136,7 +135,7 @@ def {test} string_tail(!s:string, ?str:string) { | else :: fail } } - string_tail(!s, ?str:string) + !string_tail(?str:string) # this should work... # ?str = [c | str] ?str = string(c) ,, str @@ -144,62 +143,61 @@ def {test} string_tail(!s:string, ?str:string) { ## bool/2 # Parse a JSON Boolean, followed by whitespace. -def {test} bool(!s:string, ?bool:_) { - string_token("false", !s) +def {test} bool(?bool:_) use !tokens { + !literal("false") ?bool = jbool(false) - | string_token("true", !s) + | !literal("true") ?bool = jbool(true) } ## number/2 # Parse a JSON number, followed by whitespace. -def {test} number(!s:string, ?number:_) { - digit(!s, ?n) - digits(!s, _, !n) - if { char('.', !s) :: - digit(!s, ?f) - digits(!s, ?len, !f) +def {test} number(?number:_) use !tokens { + !digit(?n) + !digits(_, !n) + if { !char('.') :: + !digit(?f) + !digits(?len, !f) !n += f / power(10.0, len) } - if { { char('e', !s) | char('E', !s) } :: - digit(!s, ?e) - digits(!s, _, !e) + if { { !char('e') | !char('E') } :: + !digit(?e) + !digits(_, !e) !n *= power(10.0, e) } - space(!s) + !space ?number = jnumber(n) } ## digits/3 # Parse a sequence of digits, outputting the number of digits parsed -def {test} digits(!s:string, ?len:float, !n:float) { - digit(!s, ?d) +def {test} digits(?len:float, !n:float) use !tokens { + !digit(?d) ?n = n * 10.0 + d - digits(!s, ?len, !n) + !digits(?len, !n) !len += 1.0 | ?len = 1.0 } ## digits/3 -# Parse a single digit digits -def {test} digit(!s:string, ?d:float) { - [?c | ?rest] = s +# Parse a single digit +def {test} digit(?d:float) use !tokens { + !char(?c) '0' <= c & c <= '9' - ?s = rest - ?d = foreign llvm sitofp(ord(c) - ord('0')) + ?d = foreign llvm sitofp(ord(c) - ord('0'):int) } ## list/2 # Parse a JSON list, followed by whitespace. -def {test} list(!s:string, ?list:_) { - sequence('[', json, !s, ?js, ']') +def {test} list(?list:_) use !tokens { + !sequence('[', json, ?js, ']') ?list = jlist(js) } ## null/2 # Parse a JSON null, followed by whitespace. -def {test} null(!s:string) { - string_token("null", !s) +def {test} null() use !tokens { + !literal("null") } pub def print(x:_) use !io { @@ -214,28 +212,24 @@ def print(ind:int, x:_) use !io { !indent(@1) !escape(@2^key) !print(": ") - !print(@1 + 1, @2^value) + !print(@1, @2^value) }, ind, pairs, '}') | jlist(?list) :: !print_list('[', {resource}{ !indent(@1) !print(@1, @2) }, ind, list, ']') - | jstring(?s) :: - !escape(s) - | jbool(?b) :: - !print(b) - | jnumber(?n) :: - !print(n) - | else :: - !print("null") + | jstring(?s) :: !escape(s) + | jbool(?b) :: !print(b) + | jnumber(?n) :: !print(n) + | else :: !print("null") } } def indent(ind:int) use !io { - for _ in 0..ind { - !print(" ") - } + ind <= 0 + | !print(" ") + !indent(ind - 1) } def escape(s:string) use !io { @@ -269,9 +263,10 @@ def print_list(start:char, printer:{resource}(int, X), ind:int, xs:list(X), end: !print(end) } -?s = "{\"ab\\nc\" : [false, true, 123.098, 123, 123.456e10], \"def\": null}" +?s = "{\"a\": [1, 1.2, 1e2, false, null], \"abc\ndef\": true}" if { parse(!s, ?j) :: + !println("successfully parsed: ") !print(j) - | else :: - !error("failed to parse") + | else :: + !error("failed to parse $(s)") } \ No newline at end of file From ec6b059616bbdd325064c6644988f0bc4f53257e Mon Sep 17 00:00:00 2001 From: James Barnes Date: Sun, 29 Sep 2024 00:32:50 +1000 Subject: [PATCH 06/19] Naming things --- samples/json.wybe | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 47850249..96376524 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -73,10 +73,10 @@ def {test} json(?j:_) use !tokens { ## sequence/5 # Parse a comma-separated sequence of things, with a preceding and # following character, followed by whitespace. -def {test} sequence(before:char, parse:{resource,test}(?X), ?xs:list(X), after:char) use !tokens { +def {test} sequence(before:char, item:{resource,test}(?X), ?xs:list(X), after:char) use !tokens { !literal(before) - if { parse(?x) :: - !sequence_tail(parse, ?xs) + if { item(?x) :: + !sequence_tail(item, ?xs) ?xs = [x | xs] | else :: ?xs = [] @@ -86,10 +86,10 @@ def {test} sequence(before:char, parse:{resource,test}(?X), ?xs:list(X), after:c ## sequence_tail/3 # Parse the tail of a sequnece. Helper for sequence/2. -def {test} sequence_tail(parse:{resource,test}(?X), ?xs:list(X)) use !tokens { +def {test} sequence_tail(item:{resource,test}(?X), ?xs:list(X)) use !tokens { if { !literal(',') :: - !parse(?x) - !sequence_tail(parse, ?xs) + !item(?x) + !sequence_tail(item, ?xs) ?xs = [x | xs] | else :: ?xs = [] From 6ea7cc561b7b9be0d45bcd5b6912ae45c05db0f8 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Mon, 30 Sep 2024 19:54:00 +1000 Subject: [PATCH 07/19] Clean up IO in sample --- samples/json | Bin 0 -> 31664 bytes samples/json.wybe | 27 ++++++++++++++++----------- 2 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 samples/json diff --git a/samples/json b/samples/json new file mode 100644 index 0000000000000000000000000000000000000000..51b35033bc297d78231ffd10288bc6e42b2d0a7d GIT binary patch literal 31664 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

k>-j5F@`>mGnahcMgkUi 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 Kjw=wC)&3iHoD72i literal 0 HcmV?d00001 diff --git a/samples/json.wybe b/samples/json.wybe index 96376524..1a15bd0f 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -73,10 +73,10 @@ def {test} json(?j:_) use !tokens { ## sequence/5 # Parse a comma-separated sequence of things, with a preceding and # following character, followed by whitespace. -def {test} sequence(before:char, item:{resource,test}(?X), ?xs:list(X), after:char) use !tokens { +def {test} sequence(before:char, parse_item:{resource,test}(?X), ?xs:list(X), after:char) use !tokens { !literal(before) - if { item(?x) :: - !sequence_tail(item, ?xs) + if { parse_item(?x) :: + !sequence_tail(parse_item, ?xs) ?xs = [x | xs] | else :: ?xs = [] @@ -86,10 +86,10 @@ def {test} sequence(before:char, item:{resource,test}(?X), ?xs:list(X), after:ch ## sequence_tail/3 # Parse the tail of a sequnece. Helper for sequence/2. -def {test} sequence_tail(item:{resource,test}(?X), ?xs:list(X)) use !tokens { +def {test} sequence_tail(parse_item:{resource,test}(?X), ?xs:list(X)) use !tokens { if { !literal(',') :: - !item(?x) - !sequence_tail(item, ?xs) + !parse_item(?x) + !sequence_tail(parse_item, ?xs) ?xs = [x | xs] | else :: ?xs = [] @@ -263,10 +263,15 @@ def print_list(start:char, printer:{resource}(int, X), ind:int, xs:list(X), end: !print(end) } -?s = "{\"a\": [1, 1.2, 1e2, false, null], \"abc\ndef\": true}" -if { parse(!s, ?j) :: - !println("successfully parsed: ") - !print(j) +?str = "{\"a\": [1, 1.2, 1e2, false, null], \"abc\ndef\": true}" + +!print("Attempting to parse ") +!escape(str) +!nl + +if { parse(str, ?json) :: + !println("Successfully parsed!") + !print(json) | else :: - !error("failed to parse $(s)") + !error("failed to parse :(") } \ No newline at end of file From 876a82f8a671e14d39f9b30d7b84d05b0046959b Mon Sep 17 00:00:00 2001 From: James Barnes Date: Mon, 30 Sep 2024 22:23:37 +1000 Subject: [PATCH 08/19] handle aliases of globals properly; remove sample exe --- samples/json | Bin 31664 -> 0 bytes src/AliasAnalysis.hs | 48 +++++++++--------- .../exp/testcase_multi_specz-drone.exp | 14 +++-- .../exp/testcase_multi_specz-int_list.exp | 14 +++-- test-cases/final-dump/inline_pos.exp | 7 ++- test-cases/final-dump/main_hello.exp | 7 ++- 6 files changed, 42 insertions(+), 48 deletions(-) delete mode 100644 samples/json diff --git a/samples/json b/samples/json deleted file mode 100644 index 51b35033bc297d78231ffd10288bc6e42b2d0a7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31664 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

k>-j5F@`>mGnahcMgkUi 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 Kjw=wC)&3iHoD72i diff --git a/src/AliasAnalysis.hs b/src/AliasAnalysis.hs index 66560841..b67b7ba5 100644 --- a/src/AliasAnalysis.hs +++ b/src/AliasAnalysis.hs @@ -25,6 +25,7 @@ import Data.Tuple.Extra import Flow ((|>)) import Options (LogSelection (Analysis)) import Util +import Config (specialName2) -- This "AliasMapLocal" is used during analysis and it will be converted to @@ -39,6 +40,7 @@ import Util -- consider the corresponding parameter as interesting. data AliasMapLocalItem = LiveVar PrimVarName + | AliasByGlobal GlobalInfo | AliasByParam PrimVarName | MaybeAliasByParam PrimVarName deriving (Eq, Ord, Show) @@ -190,7 +192,7 @@ aliasedByFork caller body analysisInfo = do PrimFork _ _ _ fBodies deflt -> do logAlias ">>> Forking:" analysisInfos <- - mapM (\body' -> aliasedByBody caller body' analysisInfo) + mapM (\body' -> aliasedByBody caller body' analysisInfo) $ fBodies ++ maybeToList deflt return $ mergeAnalysisInfo analysisInfos NoFork -> do @@ -294,8 +296,8 @@ updateAliasedByPrim aliasMap prim = -- Analyse simple prims logAlias $ "--- simple prim: " ++ show prim let prim' = content prim - maybeAliasedVariables <- maybeAliasPrimArgs prim' - aliasedArgsInSimplePrim aliasMap maybeAliasedVariables + maybeAliasedPrimArgs <- maybeAliasPrimArgs prim' + aliasedArgsInSimplePrim aliasMap maybeAliasedPrimArgs (fst $ primArgs prim') @@ -304,16 +306,16 @@ updateAliasedByPrim aliasMap prim = -- Not to compute aliasing from mutate instructions with the assumption that we -- always try to do nondestructive update. -- Retruns maybeAliasedVariables -maybeAliasPrimArgs :: Prim -> Compiler [PrimVarName] +maybeAliasPrimArgs :: Prim -> Compiler [AliasMapLocalItem] maybeAliasPrimArgs (PrimForeign "lpvm" "access" _ args) = _maybeAliasPrimArgs args maybeAliasPrimArgs (PrimForeign "lpvm" "cast" _ args) = _maybeAliasPrimArgs args maybeAliasPrimArgs (PrimForeign "llvm" "move" _ args) = _maybeAliasPrimArgs args -maybeAliasPrimArgs (PrimForeign "llvm" "load" _ args) = +maybeAliasPrimArgs (PrimForeign "lpvm" "load" _ args) = _maybeAliasPrimArgs args -maybeAliasPrimArgs (PrimForeign "llvm" "store" _ args) = +maybeAliasPrimArgs (PrimForeign "lpvm" "store" _ args) = _maybeAliasPrimArgs args maybeAliasPrimArgs prim@(PrimForeign "lpvm" "mutate" flags args) = do let [fIn, fOut, _, _, _, _, mem] = args @@ -330,7 +332,7 @@ maybeAliasPrimArgs prim = return [] -- It filters the args and keeps those may aliased with others -- We don't care about the Flow of args -- since the aliasMap is undirectional -_maybeAliasPrimArgs :: [PrimArg] -> Compiler [PrimVarName] +_maybeAliasPrimArgs :: [PrimArg] -> Compiler [AliasMapLocalItem] _maybeAliasPrimArgs args = do args' <- mapM filterArg args let escapedVars = catMaybes args' @@ -338,15 +340,16 @@ _maybeAliasPrimArgs args = do where filterArg arg = case arg of - ArgVar{argVarName=var, argVarType=ty} - -> do - isPhantom <- argIsPhantom arg - rep <- lookupTypeRepresentation ty - -- Only Address type will create alias - if not isPhantom && rep == Just Address - then return $ Just var - else return Nothing - _ -> return Nothing + ArgVar{argVarName=var, argVarType=ty} -> maybeAddressAlias arg ty (LiveVar var) + ArgGlobal global ty -> maybeAddressAlias arg ty $ AliasByGlobal global + _ -> return Nothing + maybeAddressAlias arg ty item = do + isPhantom <- argIsPhantom arg + rep <- lookupTypeRepresentation ty + -- Only Address type will create alias + if not isPhantom && rep == Just Address + then return $ Just item + else return Nothing -- Check Arg aliases in one of proc calls inside a ProcBody @@ -361,18 +364,15 @@ aliasedArgsInPrimCall calleeArgsAliases currentAlias primArgs = do -- Check Arg aliases in one of the prims of a ProcBody. -- (maybeAliasedInput, maybeAliasedOutput, primArgs): argument in current prim -- that being analysed -aliasedArgsInSimplePrim :: AliasMapLocal -> [PrimVarName] -> [PrimArg] +aliasedArgsInSimplePrim :: AliasMapLocal -> [AliasMapLocalItem] -> [PrimArg] -> Compiler AliasMapLocal aliasedArgsInSimplePrim aliasMap [] primArgs = -- No new aliasing incurred but still need to cleanup final args return $ removeDeadVar aliasMap primArgs -aliasedArgsInSimplePrim aliasMap - maybeAliasedVariables primArgs = do - logAlias $ " primArgs: " ++ show primArgs - logAlias $ " maybeAliasedVariables: " - ++ show maybeAliasedVariables - let maybeAliasedVariables' = List.map LiveVar maybeAliasedVariables - let aliasMap' = addConnectedGroupToDS maybeAliasedVariables' aliasMap +aliasedArgsInSimplePrim aliasMap maybeAliasedPrimArgs primArgs = do + logAlias $ " primArgs: " ++ show primArgs + logAlias $ " maybeAliasedPrimArgs: " ++ show maybeAliasedPrimArgs + let aliasMap' = addConnectedGroupToDS maybeAliasedPrimArgs aliasMap return $ removeDeadVar aliasMap' primArgs diff --git a/test-cases/complex/exp/testcase_multi_specz-drone.exp b/test-cases/complex/exp/testcase_multi_specz-drone.exp index 72a8e8b1..a5b2696c 100644 --- a/test-cases/complex/exp/testcase_multi_specz-drone.exp +++ b/test-cases/complex/exp/testcase_multi_specz-drone.exp @@ -99,9 +99,8 @@ module top-level code > public {semipure} (0 calls) ()<{<>, <>}; {<>, <>}; {}>: AliasPairs: [] InterestingCallProperties: [] - MultiSpeczDepInfo: [(0,(wybe.array.[|]<0>,fromList [NonAliasedParamCond 2 []]))] foreign lpvm load(<>:wybe.array(wybe.c_string), ?%arguments##0:wybe.array(wybe.c_string)) - wybe.array.[|]<0>[785a827a1b](?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn + wybe.array.[|]<0>(?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn case ~tmp#8##0:wybe.bool of 0: foreign c {terminal,semipure} error_exit(c"command_line:18:15":wybe.c_string, c"Erroneous program argument vector":wybe.c_string) @command_line:nn:nn @@ -151,7 +150,7 @@ set_exit_code(code##0:wybe.int)<{}; {<>}; {}>: declare external ccc void @error_exit(i64, i64) -declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64) +declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64) declare external ccc i8* @wybe_malloc(i32) @@ -163,7 +162,7 @@ declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) define external fastcc void @"command_line.<0>"() { entry: %0 = load i64, i64* @"resource#command_line.arguments" - %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64 %0) + %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64 %0) %2 = extractvalue {i64, i64, i1} %1, 0 %3 = extractvalue {i64, i64, i1} %1, 1 %4 = extractvalue {i64, i64, i1} %1, 2 @@ -760,9 +759,8 @@ module top-level code > public {semipure} (0 calls) ()<{<>, <>}; {<>, <>}; {}>: AliasPairs: [] InterestingCallProperties: [] - MultiSpeczDepInfo: [(0,(wybe.array.[|]<0>,fromList [NonAliasedParamCond 2 []]))] foreign lpvm load(<>:wybe.array(wybe.c_string), ?%arguments##0:wybe.array(wybe.c_string)) - wybe.array.[|]<0>[785a827a1b](?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn + wybe.array.[|]<0>(?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn case ~tmp#8##0:wybe.bool of 0: foreign c {terminal,semipure} error_exit(c"command_line:18:15":wybe.c_string, c"Erroneous program argument vector":wybe.c_string) @command_line:nn:nn @@ -812,7 +810,7 @@ set_exit_code(code##0:wybe.int)<{}; {<>}; {}>: declare external ccc void @error_exit(i64, i64) -declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64) +declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64) declare external ccc i8* @wybe_malloc(i32) @@ -824,7 +822,7 @@ declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) define external fastcc void @"command_line.<0>"() { entry: %0 = load i64, i64* @"resource#command_line.arguments" - %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64 %0) + %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64 %0) %2 = extractvalue {i64, i64, i1} %1, 0 %3 = extractvalue {i64, i64, i1} %1, 1 %4 = extractvalue {i64, i64, i1} %1, 2 diff --git a/test-cases/complex/exp/testcase_multi_specz-int_list.exp b/test-cases/complex/exp/testcase_multi_specz-int_list.exp index b39e0590..7e23b666 100644 --- a/test-cases/complex/exp/testcase_multi_specz-int_list.exp +++ b/test-cases/complex/exp/testcase_multi_specz-int_list.exp @@ -168,9 +168,8 @@ module top-level code > public {semipure} (0 calls) ()<{<>, <>}; {<>, <>}; {}>: AliasPairs: [] InterestingCallProperties: [] - MultiSpeczDepInfo: [(0,(wybe.array.[|]<0>,fromList [NonAliasedParamCond 2 []]))] foreign lpvm load(<>:wybe.array(wybe.c_string), ?%arguments##0:wybe.array(wybe.c_string)) - wybe.array.[|]<0>[785a827a1b](?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn + wybe.array.[|]<0>(?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn case ~tmp#8##0:wybe.bool of 0: foreign c {terminal,semipure} error_exit(c"command_line:18:15":wybe.c_string, c"Erroneous program argument vector":wybe.c_string) @command_line:nn:nn @@ -220,7 +219,7 @@ set_exit_code(code##0:wybe.int)<{}; {<>}; {}>: declare external ccc void @error_exit(i64, i64) -declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64) +declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64) declare external ccc i8* @wybe_malloc(i32) @@ -232,7 +231,7 @@ declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) define external fastcc void @"command_line.<0>"() { entry: %0 = load i64, i64* @"resource#command_line.arguments" - %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64 %0) + %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64 %0) %2 = extractvalue {i64, i64, i1} %1, 0 %3 = extractvalue {i64, i64, i1} %1, 1 %4 = extractvalue {i64, i64, i1} %1, 2 @@ -1120,9 +1119,8 @@ module top-level code > public {semipure} (0 calls) ()<{<>, <>}; {<>, <>}; {}>: AliasPairs: [] InterestingCallProperties: [] - MultiSpeczDepInfo: [(0,(wybe.array.[|]<0>,fromList [NonAliasedParamCond 2 []]))] foreign lpvm load(<>:wybe.array(wybe.c_string), ?%arguments##0:wybe.array(wybe.c_string)) - wybe.array.[|]<0>[785a827a1b](?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn + wybe.array.[|]<0>(?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn case ~tmp#8##0:wybe.bool of 0: foreign c {terminal,semipure} error_exit(c"command_line:18:15":wybe.c_string, c"Erroneous program argument vector":wybe.c_string) @command_line:nn:nn @@ -1172,7 +1170,7 @@ set_exit_code(code##0:wybe.int)<{}; {<>}; {}>: declare external ccc void @error_exit(i64, i64) -declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64) +declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64) declare external ccc i8* @wybe_malloc(i32) @@ -1184,7 +1182,7 @@ declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) define external fastcc void @"command_line.<0>"() { entry: %0 = load i64, i64* @"resource#command_line.arguments" - %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64 %0) + %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64 %0) %2 = extractvalue {i64, i64, i1} %1, 0 %3 = extractvalue {i64, i64, i1} %1, 1 %4 = extractvalue {i64, i64, i1} %1, 2 diff --git a/test-cases/final-dump/inline_pos.exp b/test-cases/final-dump/inline_pos.exp index b338c661..09ed2fc6 100644 --- a/test-cases/final-dump/inline_pos.exp +++ b/test-cases/final-dump/inline_pos.exp @@ -23,9 +23,8 @@ module top-level code > public {semipure} (0 calls) ()<{<>, <>}; {<>, <>}; {}>: AliasPairs: [] InterestingCallProperties: [] - MultiSpeczDepInfo: [(0,(wybe.array.[|]<0>,fromList [NonAliasedParamCond 2 []]))] foreign lpvm load(<>:wybe.array(wybe.c_string), ?%arguments##0:wybe.array(wybe.c_string)) - wybe.array.[|]<0>[785a827a1b](?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn + wybe.array.[|]<0>(?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn case ~tmp#8##0:wybe.bool of 0: foreign c {terminal,semipure} error_exit(c"command_line:18:15":wybe.c_string, c"Erroneous program argument vector":wybe.c_string) @command_line:nn:nn @@ -75,7 +74,7 @@ set_exit_code(code##0:wybe.int)<{}; {<>}; {}>: declare external ccc void @error_exit(i64, i64) -declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64) +declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64) declare external ccc i8* @wybe_malloc(i32) @@ -87,7 +86,7 @@ declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) define external fastcc void @"command_line.<0>"() { entry: %0 = load i64, i64* @"resource#command_line.arguments" - %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64 %0) + %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64 %0) %2 = extractvalue {i64, i64, i1} %1, 0 %3 = extractvalue {i64, i64, i1} %1, 1 %4 = extractvalue {i64, i64, i1} %1, 2 diff --git a/test-cases/final-dump/main_hello.exp b/test-cases/final-dump/main_hello.exp index b2f2d2d6..4833cb4d 100644 --- a/test-cases/final-dump/main_hello.exp +++ b/test-cases/final-dump/main_hello.exp @@ -23,9 +23,8 @@ module top-level code > public {semipure} (0 calls) ()<{<>, <>}; {<>, <>}; {}>: AliasPairs: [] InterestingCallProperties: [] - MultiSpeczDepInfo: [(0,(wybe.array.[|]<0>,fromList [NonAliasedParamCond 2 []]))] foreign lpvm load(<>:wybe.array(wybe.c_string), ?%arguments##0:wybe.array(wybe.c_string)) - wybe.array.[|]<0>[785a827a1b](?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn + wybe.array.[|]<0>(?command##1:wybe.c_string, ?arguments##2:wybe.array(wybe.c_string), ~arguments##0:wybe.array(wybe.c_string), ?tmp#8##0:wybe.bool) #0 @command_line:nn:nn case ~tmp#8##0:wybe.bool of 0: foreign c {terminal,semipure} error_exit(c"command_line:18:15":wybe.c_string, c"Erroneous program argument vector":wybe.c_string) @command_line:nn:nn @@ -75,7 +74,7 @@ set_exit_code(code##0:wybe.int)<{}; {<>}; {}>: declare external ccc void @error_exit(i64, i64) -declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64) +declare external fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64) declare external ccc i8* @wybe_malloc(i32) @@ -87,7 +86,7 @@ declare external ccc void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i1) define external fastcc void @"command_line.<0>"() { entry: %0 = load i64, i64* @"resource#command_line.arguments" - %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>[785a827a1b]"(i64 %0) + %1 = tail call fastcc {i64, i64, i1} @"wybe.array.[|]<0>"(i64 %0) %2 = extractvalue {i64, i64, i1} %1, 0 %3 = extractvalue {i64, i64, i1} %1, 1 %4 = extractvalue {i64, i64, i1} %1, 2 From ec2f54dd46ea424fff05ac538f6cf30646788032 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Tue, 1 Oct 2024 20:10:50 +1000 Subject: [PATCH 09/19] Organise json sample; address comments --- samples/json.wybe | 159 +++++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 72 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 1a15bd0f..b6d70da2 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -55,7 +55,9 @@ def {test} literal(str:string) use !tokens { ## space/1 # Parse zero or more whitespace characters from the input. def space() use !tokens { - !char(?c) & (c = ' ' | c = '\n' | c = '\r' | c = '\t') + !char(?c) + (c = ' ' | c = '\n' | c = '\r' | c = '\t') + !space | pass } @@ -63,17 +65,75 @@ def space() use !tokens { # Parse a JSON object followed by whitespace. def {test} json(?j:_) use !tokens { !object(?j) - | !string(?str) & ?j = jstring(str) + | !list(?j) + | !string(?j) | !bool(?j) | !number(?j) - | !list(?j) - | !null & ?j = jnull + | !null(?j) +} + +## object/1 +# Parse a JSON object, followed by whitespace. +def {test} object(?obj:_) use !tokens { + !sequence('{', {test,resource}{ + !string(?key) + !literal(':') + !json(?value) + ?@ = pair(key, value) + }, '}', ?pairs) + ?obj = jobject(pairs) +} + +## list/1 +# Parse a JSON list, followed by whitespace. +def {test} list(?list:_) use !tokens { + !sequence('[', json, ']', ?jsons) + ?list = jlist(jsons) +} + +## string/1 +# Parse a JSON string, followed by whitespace. +def {test} string(?string:_) use !tokens { + !string(?str) + ?string = jstring(str) +} + +## number/1 +# Parse a JSON number, followed by whitespace. +def {test} number(?number:_) use !tokens { + !digits(?n, _) + if { !char('.') :: + !digits(?f, ?len) + !n += f / power(10.0, len) + } + if { { !char('e') | !char('E') } :: + !digits(?e, _) + !n *= power(10.0, e) + } + !space + ?number = jnumber(n) +} + +## bool/1 +# Parse a JSON Boolean, followed by whitespace. +def {test} bool(?bool:_) use !tokens { + !literal("false") + ?bool = jbool(false) + | !literal("true") + ?bool = jbool(true) +} + +## null/1 +# Parse a JSON null, followed by whitespace. +def {test} null(?null:_) use !tokens { + !literal("null") + ?null = jnull } -## sequence/5 +## sequence/4 # Parse a comma-separated sequence of things, with a preceding and # following character, followed by whitespace. -def {test} sequence(before:char, parse_item:{resource,test}(?X), ?xs:list(X), after:char) use !tokens { +def {test} sequence(before:char, parse_item:{resource,test}(?X), after:char, ?xs:list(X)) use !tokens { !literal(before) if { parse_item(?x) :: !sequence_tail(parse_item, ?xs) @@ -84,8 +144,8 @@ def {test} sequence(before:char, parse_item:{resource,test}(?X), ?xs:list(X), af !literal(after) } -## sequence_tail/3 -# Parse the tail of a sequnece. Helper for sequence/2. +## sequence_tail/2 +# Parse the tail of a sequnece. Helper for sequence/4. def {test} sequence_tail(parse_item:{resource,test}(?X), ?xs:list(X)) use !tokens { if { !literal(',') :: !parse_item(?x) @@ -96,19 +156,7 @@ def {test} sequence_tail(parse_item:{resource,test}(?X), ?xs:list(X)) use !token } } -## object/2 -# Parse a JSON object, followed by whitespace. -def {test} object(?obj:_) use !tokens { - !sequence('{', {test,resource}{ - !string(?key) - !literal(':') - !json(?value) - ?@ = pair(key, value) - }, ?ps, '}') - ?obj = jobject(ps) -} - -## string/2 +## string/1 # Parse a string, followed by whitespace. def {test} string(?str:string) use !tokens { !char('\"') @@ -116,8 +164,8 @@ def {test} string(?str:string) use !tokens { ?str = string(c_string(str)) } -## string_tail/2 -# Parse the tail of a string. Helper for string/2. +## string_tail/1 +# Parse the tail of a string. Helper for string/1. def {test} string_tail(?str:string) use !tokens { !literal('\"') ?str = "" @@ -141,45 +189,15 @@ def {test} string_tail(?str:string) use !tokens { ?str = string(c) ,, str } -## bool/2 -# Parse a JSON Boolean, followed by whitespace. -def {test} bool(?bool:_) use !tokens { - !literal("false") - ?bool = jbool(false) - | !literal("true") - ?bool = jbool(true) -} - -## number/2 -# Parse a JSON number, followed by whitespace. -def {test} number(?number:_) use !tokens { +## digits/2 +# Parse a sequence of one or more digits +def {test} digits(?n:float, ?len:float) use !tokens { !digit(?n) - !digits(_, !n) - if { !char('.') :: - !digit(?f) - !digits(?len, !f) - !n += f / power(10.0, len) - } - if { { !char('e') | !char('E') } :: - !digit(?e) - !digits(_, !e) - !n *= power(10.0, e) - } - !space - ?number = jnumber(n) -} - -## digits/3 -# Parse a sequence of digits, outputting the number of digits parsed -def {test} digits(?len:float, !n:float) use !tokens { - !digit(?d) - ?n = n * 10.0 + d - !digits(?len, !n) - !len += 1.0 - | ?len = 1.0 + ?len = 1.0 + !digits(!n, !len) } -## digits/3 +## digits/1 # Parse a single digit def {test} digit(?d:float) use !tokens { !char(?c) @@ -187,17 +205,14 @@ def {test} digit(?d:float) use !tokens { ?d = foreign llvm sitofp(ord(c) - ord('0'):int) } -## list/2 -# Parse a JSON list, followed by whitespace. -def {test} list(?list:_) use !tokens { - !sequence('[', json, ?js, ']') - ?list = jlist(js) -} - -## null/2 -# Parse a JSON null, followed by whitespace. -def {test} null() use !tokens { - !literal("null") +## digits/2 +# Parse a sequence of zero or more digits. Helper for digits/2 +def {test} digits(!n:float, !len:float) use !tokens { + !digit(?d) + !len += 1.0 + ?n = n * 10.0 + d + !digits(!len, !n) + | pass } pub def print(x:_) use !io { @@ -263,7 +278,7 @@ def print_list(start:char, printer:{resource}(int, X), ind:int, xs:list(X), end: !print(end) } -?str = "{\"a\": [1, 1.2, 1e2, false, null], \"abc\ndef\": true}" +?str = "{\"a\": [1, 1.2, 1e2, false, null],\n \"abc\\ndef\": true}" !print("Attempting to parse ") !escape(str) @@ -273,5 +288,5 @@ if { parse(str, ?json) :: !println("Successfully parsed!") !print(json) | else :: - !error("failed to parse :(") + !print("failed to parse :(") } \ No newline at end of file From 2ac93e4d76df983290d4a450eed022516762c39d Mon Sep 17 00:00:00 2001 From: James Barnes Date: Tue, 1 Oct 2024 20:15:19 +1000 Subject: [PATCH 10/19] Fix string prepend; name digits_ more clearly --- samples/json.wybe | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index b6d70da2..7aa77678 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -183,10 +183,8 @@ def {test} string_tail(?str:string) use !tokens { | else :: fail } } - !string_tail(?str:string) - # this should work... - # ?str = [c | str] - ?str = string(c) ,, str + !string_tail(?str) + ?str = c ,, str } ## digits/2 @@ -194,7 +192,7 @@ def {test} string_tail(?str:string) use !tokens { def {test} digits(?n:float, ?len:float) use !tokens { !digit(?n) ?len = 1.0 - !digits(!n, !len) + !digits_(!n, !len) } ## digits/1 @@ -205,9 +203,9 @@ def {test} digit(?d:float) use !tokens { ?d = foreign llvm sitofp(ord(c) - ord('0'):int) } -## digits/2 +## digits_/2 # Parse a sequence of zero or more digits. Helper for digits/2 -def {test} digits(!n:float, !len:float) use !tokens { +def {test} digits_(!n:float, !len:float) use !tokens { !digit(?d) !len += 1.0 ?n = n * 10.0 + d From 4e58e5486b7e67aefc04ac59c5a6410f3dc2ec88 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Tue, 1 Oct 2024 20:46:04 +1000 Subject: [PATCH 11/19] Require ! for rsourceful HO calls --- samples/json.wybe | 2 +- src/Resources.hs | 10 +++++++--- test-cases/final-dump/global_flow_inference.wybe | 8 ++++---- test-cases/final-dump/ho_resources_no_bang.exp | 3 +++ test-cases/final-dump/ho_resources_no_bang.wybe | 6 ++++++ 5 files changed, 21 insertions(+), 8 deletions(-) create mode 100644 test-cases/final-dump/ho_resources_no_bang.exp create mode 100644 test-cases/final-dump/ho_resources_no_bang.wybe diff --git a/samples/json.wybe b/samples/json.wybe index 7aa77678..5be84ec7 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -135,7 +135,7 @@ def {test} null(?null:_) use !tokens { # following character, followed by whitespace. def {test} sequence(before:char, parse_item:{resource,test}(?X), after:char, ?xs:list(X)) use !tokens { !literal(before) - if { parse_item(?x) :: + if { !parse_item(?x) :: !sequence_tail(parse_item, ?xs) ?xs = [x | xs] | else :: diff --git a/src/Resources.hs b/src/Resources.hs index 4e55df4e..504d5dea 100644 --- a/src/Resources.hs +++ b/src/Resources.hs @@ -334,14 +334,18 @@ transformStmt stmt@(ProcCall fn@(First m n mbId) d resourceful args) pos = do return (loadStoreResources pos ins outs [ProcCall fn d False (args'' ++ resArgs) `maybePlace` pos], usesResources || not (Map.null outs)) -transformStmt (ProcCall (Higher fn) d r args) pos = do +transformStmt stmt@(ProcCall (Higher fn) d resourceful args) pos = do (fn':args', ins, outs) <- transformExps $ fn:args - let globals = case maybeExpType $ content fn' of + let usesResources = case maybeExpType $ content fn' of Just (HigherOrderType mods _) -> modifierResourceful mods _ -> shouldnt "glabalise badly typed higher" + when (usesResources && not resourceful) + $ lift $ errmsg pos + $ "Call to resourceful higher-order proc without ! resource marker: " + ++ showStmt 4 stmt return (loadStoreResources pos ins outs [ProcCall (Higher fn') d False args' `maybePlace` pos], - globals) + usesResources) transformStmt (ForeignCall lang name flags args) pos = do (args', ins, outs) <- transformExps args return (loadStoreResources pos ins outs diff --git a/test-cases/final-dump/global_flow_inference.wybe b/test-cases/final-dump/global_flow_inference.wybe index c1516a45..80ec609a 100644 --- a/test-cases/final-dump/global_flow_inference.wybe +++ b/test-cases/final-dump/global_flow_inference.wybe @@ -37,21 +37,21 @@ def {noinline} rec_out_only_notail2 use !res { } def {noinline} higher_order_inout(f:{resource}(int)) use !res { - f(res) + !f(res) ?res = 1 } def {noinline} higher_order_in(f:{resource}(int)) use !res { - f(res) + !f(res) } def {noinline} higher_order_out(f:{resource}(?int)) use !res { - f(?res) + !f(?res) } def {noinline} higher_order_only_out(f:{resource}(int)) use !res { ?res = 1 - f(res) + !f(res) } def {noinline} higher_order_branch(b:bool, f:{resource}()) { diff --git a/test-cases/final-dump/ho_resources_no_bang.exp b/test-cases/final-dump/ho_resources_no_bang.exp new file mode 100644 index 00000000..d05bd6ed --- /dev/null +++ b/test-cases/final-dump/ho_resources_no_bang.exp @@ -0,0 +1,3 @@ +Error detected during resource checking of module(s) ho_resources_no_bang +final-dump/ho_resources_no_bang.wybe:6:1: Call to resourceful higher-order proc without ! resource marker: f:{resource}() @ho_resources_no_bang:nn:nn + diff --git a/test-cases/final-dump/ho_resources_no_bang.wybe b/test-cases/final-dump/ho_resources_no_bang.wybe new file mode 100644 index 00000000..5be451aa --- /dev/null +++ b/test-cases/final-dump/ho_resources_no_bang.wybe @@ -0,0 +1,6 @@ +def foo() use !io { + pass +} + +?f = foo +f From 923adf3600af67a851e3d1151cc0d65e7208ac03 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Tue, 1 Oct 2024 20:47:54 +1000 Subject: [PATCH 12/19] Refactor digits into a loop --- samples/json.wybe | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 5be84ec7..65f4e7dd 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -192,7 +192,12 @@ def {test} string_tail(?str:string) use !tokens { def {test} digits(?n:float, ?len:float) use !tokens { !digit(?n) ?len = 1.0 - !digits_(!n, !len) + do { + !digit(?d) + !len += 1.0 + ?n = n * 10.0 + d + | break + } } ## digits/1 @@ -203,16 +208,6 @@ def {test} digit(?d:float) use !tokens { ?d = foreign llvm sitofp(ord(c) - ord('0'):int) } -## digits_/2 -# Parse a sequence of zero or more digits. Helper for digits/2 -def {test} digits_(!n:float, !len:float) use !tokens { - !digit(?d) - !len += 1.0 - ?n = n * 10.0 + d - !digits(!len, !n) - | pass -} - pub def print(x:_) use !io { !print(0, x) !nl @@ -276,7 +271,7 @@ def print_list(start:char, printer:{resource}(int, X), ind:int, xs:list(X), end: !print(end) } -?str = "{\"a\": [1, 1.2, 1e2, false, null],\n \"abc\\ndef\": true}" +?str = " {\"a\": [1, 1.020, 1e2, 01.2E3, false, { \"key\": null}],\n \"abc\\ndef\": true } " !print("Attempting to parse ") !escape(str) From 36e8f277c90fe11299f87e0b27c49b70e703dae9 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Tue, 1 Oct 2024 20:57:32 +1000 Subject: [PATCH 13/19] Newline EOF; casing --- samples/json.wybe | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 65f4e7dd..47b35bd9 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -281,5 +281,5 @@ if { parse(str, ?json) :: !println("Successfully parsed!") !print(json) | else :: - !print("failed to parse :(") -} \ No newline at end of file + !print("Failed to parse :(") +} From a4f35cb552a171399562040eeccaa4c73a693d6d Mon Sep 17 00:00:00 2001 From: James Barnes Date: Tue, 1 Oct 2024 21:00:47 +1000 Subject: [PATCH 14/19] remove imports --- samples/json.wybe | 3 --- 1 file changed, 3 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 47b35bd9..81e32ced 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -1,6 +1,3 @@ -use wybe.float -use logging - pub constructors jobject(list(pair)) | jstring(string) | jbool(bool) From 1f08449febc6ee56942941bc6cdecc78eb230722 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Wed, 2 Oct 2024 23:22:10 +1000 Subject: [PATCH 15/19] Better document samples/json; add more tests to samples/json --- samples/json.wybe | 132 +++++++++++++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 43 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 81e32ced..ffad109e 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -1,20 +1,29 @@ -pub constructors jobject(list(pair)) - | jstring(string) - | jbool(bool) - | jnumber(float) - | jlist(list(_)) - | jnull +## json.Wybe +## Author: James Barnes +# +# A recursive-descent parser for JSON documents in Wybe. + +pub constructors + jobject(list(pair)) + | jlist(list(_)) + | jstring(string) + | jnumber(float) + | jbool(bool) + | jnull +# XXX this can be removed once we get typeclasses pub def {test} (a:_ = b:_) { foreign lpvm cast(a):int = foreign lpvm cast(b):int } +## pair type +# A pair containing a key and a JSON value. pub type pair { - ## pair type - # A pair contianing a key and value. pub pair(key:string, value:json) } +## resource tokens +# Represents the tokens that remain to parse, a sequence of characters. resource tokens:string ## parse/2 @@ -24,23 +33,24 @@ pub def {test} parse(tokens:string, ?json:_) { use tokens in { !space !json(?json) + tokens = "" } } -## char/2 +## char/2 use !tokens # Parse a single character from the input string. def {test} char(?c:char) use !tokens { tokens = [?c | ?tokens] } -## literal/2 +## literal/2 use !tokens # Parse a character literal followed by whitespace. def {test} literal(c:char) use !tokens { !char(c) !space } -## literal/2 +## literal/2 use !tokens # Parse a string literal followed by whitespace. def {test} literal(str:string) use !tokens { for ?c in str { @@ -49,7 +59,7 @@ def {test} literal(str:string) use !tokens { !space } -## space/1 +## space/1 use !tokens # Parse zero or more whitespace characters from the input. def space() use !tokens { !char(?c) @@ -58,18 +68,18 @@ def space() use !tokens { | pass } -## json/1 -# Parse a JSON object followed by whitespace. +## json/1 use !tokens +# Parse a JSON value followed by whitespace. def {test} json(?j:_) use !tokens { !object(?j) | !list(?j) | !string(?j) - | !bool(?j) | !number(?j) + | !bool(?j) | !null(?j) } -## object/1 +## object/1 use !tokens # Parse a JSON object, followed by whitespace. def {test} object(?obj:_) use !tokens { !sequence('{', {test,resource}{ @@ -81,21 +91,21 @@ def {test} object(?obj:_) use !tokens { ?obj = jobject(pairs) } -## list/1 +## list/1 use !tokens # Parse a JSON list, followed by whitespace. def {test} list(?list:_) use !tokens { !sequence('[', json, ']', ?jsons) ?list = jlist(jsons) } -## string/1 +## string/1 use !tokens # Parse a JSON string, followed by whitespace. def {test} string(?string:_) use !tokens { !string(?str) ?string = jstring(str) } -## number/1 +## number/1 use !tokens # Parse a JSON number, followed by whitespace. def {test} number(?number:_) use !tokens { !digits(?n, _) @@ -111,7 +121,7 @@ def {test} number(?number:_) use !tokens { ?number = jnumber(n) } -## bool/1 +## bool/1 use !tokens # Parse a JSON Boolean, followed by whitespace. def {test} bool(?bool:_) use !tokens { !literal("false") @@ -120,14 +130,14 @@ def {test} bool(?bool:_) use !tokens { ?bool = jbool(true) } -## null/1 +## null/1 use !tokens # Parse a JSON null, followed by whitespace. def {test} null(?null:_) use !tokens { !literal("null") ?null = jnull } -## sequence/4 +## sequence/4 use !tokens # Parse a comma-separated sequence of things, with a preceding and # following character, followed by whitespace. def {test} sequence(before:char, parse_item:{resource,test}(?X), after:char, ?xs:list(X)) use !tokens { @@ -141,7 +151,7 @@ def {test} sequence(before:char, parse_item:{resource,test}(?X), after:char, ?xs !literal(after) } -## sequence_tail/2 +## sequence_tail/2 use !tokens # Parse the tail of a sequnece. Helper for sequence/4. def {test} sequence_tail(parse_item:{resource,test}(?X), ?xs:list(X)) use !tokens { if { !literal(',') :: @@ -153,7 +163,7 @@ def {test} sequence_tail(parse_item:{resource,test}(?X), ?xs:list(X)) use !token } } -## string/1 +## string/1 use !tokens # Parse a string, followed by whitespace. def {test} string(?str:string) use !tokens { !char('\"') @@ -161,7 +171,7 @@ def {test} string(?str:string) use !tokens { ?str = string(c_string(str)) } -## string_tail/1 +## string_tail/1 use !tokens # Parse the tail of a string. Helper for string/1. def {test} string_tail(?str:string) use !tokens { !literal('\"') @@ -184,7 +194,7 @@ def {test} string_tail(?str:string) use !tokens { ?str = c ,, str } -## digits/2 +## digits/2 use !tokens # Parse a sequence of one or more digits def {test} digits(?n:float, ?len:float) use !tokens { !digit(?n) @@ -197,7 +207,7 @@ def {test} digits(?n:float, ?len:float) use !tokens { } } -## digits/1 +## digits/1 use !tokens # Parse a single digit def {test} digit(?d:float) use !tokens { !char(?c) @@ -205,25 +215,30 @@ def {test} digit(?d:float) use !tokens { ?d = foreign llvm sitofp(ord(c) - ord('0'):int) } +## print/1 use !io +# Pretty print a JSON value pub def print(x:_) use !io { !print(0, x) !nl } +## print/2 use !io +# Pretty print a JSON value at a given indentation level. +# Helper for print/1. def print(ind:int, x:_) use !io { case x in { jobject(?pairs) :: - !print_list('{', {resource}{ + !print_list(ind, '{', {resource}{ !indent(@1) !escape(@2^key) !print(": ") !print(@1, @2^value) - }, ind, pairs, '}') + }, '}', pairs) | jlist(?list) :: - !print_list('[', {resource}{ + !print_list(ind, '[', {resource}{ !indent(@1) !print(@1, @2) - }, ind, list, ']') + }, ']', list) | jstring(?s) :: !escape(s) | jbool(?b) :: !print(b) | jnumber(?n) :: !print(n) @@ -231,12 +246,16 @@ def print(ind:int, x:_) use !io { } } +## indent/1 use !io +# Print a given amount of indentation def indent(ind:int) use !io { ind <= 0 - | !print(" ") + | !print(' ') !indent(ind - 1) } +## escape/1 use !io +# Print an string, with quotes and necessary characters escaped def escape(s:string) use !io { !print('"') for ?c in s { @@ -253,7 +272,9 @@ def escape(s:string) use !io { !print('"') } -def print_list(start:char, printer:{resource}(int, X), ind:int, xs:list(X), end:char) use !io { +## print_list/1 +# Pretty print a list of things with a givn printer, surroundd by a start and end character +def print_list(ind:int, start:char, printer:{resource}(int, X), end:char, xs:list(X)) use !io { !print(start) if { [?x | ?xs] = xs :: !nl @@ -268,15 +289,40 @@ def print_list(start:char, printer:{resource}(int, X), ind:int, xs:list(X), end: !print(end) } -?str = " {\"a\": [1, 1.020, 1e2, 01.2E3, false, { \"key\": null}],\n \"abc\\ndef\": true } " +########### +# TESTING +########### -!print("Attempting to parse ") -!escape(str) -!nl - -if { parse(str, ?json) :: - !println("Successfully parsed!") - !print(json) - | else :: - !print("Failed to parse :(") +type test { + pub case(should_parse:bool, document:string) } + +?tests = [ + # these should parse + case(true, "{}"), + case(true, "true"), + case(true, "[3.141596]"), + case(true, " {\"a\": [1, 1.020, 1e2, 01.2E3, false, { \"key\": null}],\n \"abc\\ndef\": true } "), + # these should fail + case(false, "definitely not JSON!"), + case(false, "\"abc"), + case(false, "{} {}") +] + +for ?test in tests { + case(?should_parse, ?document) = test + !print("Attempting to parse ") + !escape(document) + !nl + !println("Expecting $(if { should_parse :: "success" | else :: "failure" })") + + if { parse(document, ?json) :: + !println("Successfully parsed $(if { should_parse :: ":)" | else :: ":(" })") + !print(json) + | else :: + !println("Failed to parse $(if { should_parse :: ":(" | else :: ":)" })") + } + + !nl +} + From eb1d8df9da05c6e285b5654ee79c0e6c14610548 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Wed, 2 Oct 2024 23:23:02 +1000 Subject: [PATCH 16/19] Align formatting of brainfuck with json --- samples/brainfuck.wybe | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/samples/brainfuck.wybe b/samples/brainfuck.wybe index 83b1a5e4..320414f7 100644 --- a/samples/brainfuck.wybe +++ b/samples/brainfuck.wybe @@ -1,6 +1,11 @@ +## brainfuck.wybe +## Author: James Barnes +# +# A Brainfuck interpreter and LL(1) parser. + +## instruction type +# Enumeration of brainfuck instructions. type instruction { - ## instruction - # Enumeration of brainfuck instructions. pub constructors incr | decr | left | right | input | output | loop(list(_)) ## `=`/2 @@ -26,7 +31,7 @@ type instruction { # ']' should not occur if at top_level ~top_level ?instrs = [] - | else :: + | else :: ?instr = case c in { '+' :: incr | '-' :: decr @@ -34,15 +39,12 @@ type instruction { | '>' :: right | ',' :: input | '.' :: output - | '[' :: loop(body) where { - # parse the body of a loop, no longer top_level - parse(false, !str, ?body) - } + | '[' :: loop(body) where { parse(false, !str, ?body) } } parse(top_level, !str, ?instrs) ?instrs = [instr | instrs] } - | else :: + | else :: # str is empty, so must be at top_level top_level ?instrs = [] @@ -50,9 +52,9 @@ type instruction { } } +## tape type +# Infinite length tape type, with tape expanded when required. type tape { - ## tape - # Infinite length tape type, with tape expanded when required. pub tape(list(char), current:char, list(char)) ## `=`/2 @@ -69,7 +71,7 @@ type tape { tape(?left, ?current, ?right) = tape if { right = [?r | ?right] :: ?tape = tape([current | left], r, right) - | else :: + | else :: ?tape = tape([current | left], '\0', []) } } @@ -80,7 +82,7 @@ type tape { tape(?left, ?current, ?right) = tape if { left = [?l | ?left] :: ?tape = tape(left, l, [current | right]) - | else :: + | else :: ?tape = tape([], '\0', [current | right]) } } @@ -130,6 +132,6 @@ def run(instrs:list(instruction), !state:tape) use !io { if { parse(str, ?instrs) :: !run(instrs, blank_tape) - | else :: + | else :: !error("parse error") } From e7df4736393cc4f482e96ec2936e8b867f258737 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Wed, 2 Oct 2024 23:24:58 +1000 Subject: [PATCH 17/19] $ for consistency --- src/AliasAnalysis.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AliasAnalysis.hs b/src/AliasAnalysis.hs index b67b7ba5..69c37c87 100644 --- a/src/AliasAnalysis.hs +++ b/src/AliasAnalysis.hs @@ -340,7 +340,7 @@ _maybeAliasPrimArgs args = do where filterArg arg = case arg of - ArgVar{argVarName=var, argVarType=ty} -> maybeAddressAlias arg ty (LiveVar var) + ArgVar{argVarName=var, argVarType=ty} -> maybeAddressAlias arg ty $ LiveVar var ArgGlobal global ty -> maybeAddressAlias arg ty $ AliasByGlobal global _ -> return Nothing maybeAddressAlias arg ty item = do From 199360dfc204fba3bfa6603453caf57fd505a025 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Thu, 3 Oct 2024 00:03:02 +1000 Subject: [PATCH 18/19] Remove unnecessary type constraint; grammar --- samples/json.wybe | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index ffad109e..2f2e0e4c 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -177,7 +177,7 @@ def {test} string_tail(?str:string) use !tokens { !literal('\"') ?str = "" | !char(?c) - if { c:char = '\\' :: + if { c = '\\' :: !char(?c) if { c = '"' :: pass | c = '\\' :: pass @@ -195,7 +195,7 @@ def {test} string_tail(?str:string) use !tokens { } ## digits/2 use !tokens -# Parse a sequence of one or more digits +# Parse a sequence of one or more digits. def {test} digits(?n:float, ?len:float) use !tokens { !digit(?n) ?len = 1.0 @@ -208,7 +208,7 @@ def {test} digits(?n:float, ?len:float) use !tokens { } ## digits/1 use !tokens -# Parse a single digit +# Parse a single digit. def {test} digit(?d:float) use !tokens { !char(?c) '0' <= c & c <= '9' @@ -216,15 +216,14 @@ def {test} digit(?d:float) use !tokens { } ## print/1 use !io -# Pretty print a JSON value +# Pretty print a JSON value. pub def print(x:_) use !io { !print(0, x) !nl } ## print/2 use !io -# Pretty print a JSON value at a given indentation level. -# Helper for print/1. +# Pretty print a JSON value at a given indentation level. Helper for print/1. def print(ind:int, x:_) use !io { case x in { jobject(?pairs) :: @@ -247,7 +246,7 @@ def print(ind:int, x:_) use !io { } ## indent/1 use !io -# Print a given amount of indentation +# Print a given amount of indentation. def indent(ind:int) use !io { ind <= 0 | !print(' ') @@ -255,7 +254,7 @@ def indent(ind:int) use !io { } ## escape/1 use !io -# Print an string, with quotes and necessary characters escaped +# Print an string, with quotes and necessary characters escaped. def escape(s:string) use !io { !print('"') for ?c in s { @@ -273,7 +272,7 @@ def escape(s:string) use !io { } ## print_list/1 -# Pretty print a list of things with a givn printer, surroundd by a start and end character +# Pretty print a list of things with a givn printer, surrounded by a start and end character. def print_list(ind:int, start:char, printer:{resource}(int, X), end:char, xs:list(X)) use !io { !print(start) if { [?x | ?xs] = xs :: From 9a5f3e2b6a7a5cd7bca28808ee56432b787cd3e4 Mon Sep 17 00:00:00 2001 From: James Barnes Date: Thu, 3 Oct 2024 00:23:15 +1000 Subject: [PATCH 19/19] Make pair type generic; naming things --- samples/json.wybe | 51 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/samples/json.wybe b/samples/json.wybe index 2f2e0e4c..5565b314 100644 --- a/samples/json.wybe +++ b/samples/json.wybe @@ -4,7 +4,7 @@ # A recursive-descent parser for JSON documents in Wybe. pub constructors - jobject(list(pair)) + jobject(list(pair(string, _))) | jlist(list(_)) | jstring(string) | jnumber(float) @@ -17,9 +17,14 @@ pub def {test} (a:_ = b:_) { } ## pair type -# A pair containing a key and a JSON value. -pub type pair { - pub pair(key:string, value:json) +# A pair containing a key and a value. +pub type pair(K, V) { + pub pair(key:K, value:V) + + pub def {test} (a:_(K, V) = b:_(K, V)) { + foreign lpvm cast(a^key):int = foreign lpvm cast(b^key):int + foreign lpvm cast(a^value):int = foreign lpvm cast(b^value):int + } } ## resource tokens @@ -138,12 +143,12 @@ def {test} null(?null:_) use !tokens { } ## sequence/4 use !tokens -# Parse a comma-separated sequence of things, with a preceding and +# Parse a comma-separated sequence of items, with a preceding and # following character, followed by whitespace. -def {test} sequence(before:char, parse_item:{resource,test}(?X), after:char, ?xs:list(X)) use !tokens { +def {test} sequence(before:char, item:{resource,test}(?X), after:char, ?xs:list(X)) use !tokens { !literal(before) - if { !parse_item(?x) :: - !sequence_tail(parse_item, ?xs) + if { !item(?x) :: + !sequence_tail(item, ?xs) ?xs = [x | xs] | else :: ?xs = [] @@ -153,10 +158,10 @@ def {test} sequence(before:char, parse_item:{resource,test}(?X), after:char, ?xs ## sequence_tail/2 use !tokens # Parse the tail of a sequnece. Helper for sequence/4. -def {test} sequence_tail(parse_item:{resource,test}(?X), ?xs:list(X)) use !tokens { +def {test} sequence_tail(item:{resource,test}(?X), ?xs:list(X)) use !tokens { if { !literal(',') :: - !parse_item(?x) - !sequence_tail(parse_item, ?xs) + !item(?x) + !sequence_tail(item, ?xs) ?xs = [x | xs] | else :: ?xs = [] @@ -292,24 +297,19 @@ def print_list(ind:int, start:char, printer:{resource}(int, X), end:char, xs:lis # TESTING ########### -type test { - pub case(should_parse:bool, document:string) -} - ?tests = [ # these should parse - case(true, "{}"), - case(true, "true"), - case(true, "[3.141596]"), - case(true, " {\"a\": [1, 1.020, 1e2, 01.2E3, false, { \"key\": null}],\n \"abc\\ndef\": true } "), - # these should fail - case(false, "definitely not JSON!"), - case(false, "\"abc"), - case(false, "{} {}") + pair(true, "{}"), + pair(true, "true"), + pair(true, "[3.141596]"), + pair(true, " {\"a\": [1, 1.020, 1e2, 01.2E3, false, { \"key\": null}],\n \"abc\\ndef\": true } "), + # these should fail to parse + pair(false, "definitely not JSON!"), + pair(false, "\"abc"), + pair(false, "{} {}") ] -for ?test in tests { - case(?should_parse, ?document) = test +for pair(?should_parse:bool, ?document) in tests { !print("Attempting to parse ") !escape(document) !nl @@ -324,4 +324,3 @@ for ?test in tests { !nl } -