From bccfe9d8e12ba024c745cd533f73987439c76499 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 13 Oct 2017 19:41:58 -0700 Subject: [PATCH] Changed tokenizing to treat symbols as their own things. --- examples/how_do_i.nom | 37 +++++++++++++++--------- examples/sample_game.nom | 12 ++++---- lib/collections.nom | 43 ++++++++++++++++++++++------ lib/control_flow.nom | 62 ++++++++++++++++++++-------------------- lib/operators.nom | 4 +-- lib/permissions.nom | 24 ++++++++-------- lib/plurals.nom | 4 +-- nomsu.lua | 18 ++++++------ nomsu.moon | 19 ++++++------ 9 files changed, 132 insertions(+), 91 deletions(-) diff --git a/examples/how_do_i.nom b/examples/how_do_i.nom index 486ea19..2365627 100644 --- a/examples/how_do_i.nom +++ b/examples/how_do_i.nom @@ -49,7 +49,7 @@ say "Hello world!" # Use a list? %my_list = ["first item", "second item", "third item"] # Lists are 1-indexed because they're implemented as Lua tables, so this prints "first item" -say (%my_list -> 1) +say (%my_list->1) # These do the same thing: say (%my_list's 1) say (1 in %my_list) @@ -58,7 +58,12 @@ say (1 in %my_list) say (size of %my_list) # Define a dictionary/hash map? -# Dicts are created by passing a list of key-value pairs to the function "dict" +%my_dict = (dict {x = 99; y = 101}) +%my_dict = (..) + dict: + x = 101 + "99 bottles" = 99 + 653 = 292 %my_dict = (dict [["x", 99], ["y", 101]]) # Use a dict? @@ -175,11 +180,11 @@ say (first fibonacci above 10) # Functions can have aliases, which may or may not have the arguments in different order rule [..] - I hate %worse-things more than %better-things - I think %worse-things are worse than %better-things - I like %better-things more than %worse-things + I hate %worse_things more than %better_things + I think %worse_things are worse than %better_things + I like %better_things more than %worse_things ..=: - say "\(%better-things capitalized) rule and \(%worse-things) drool!" + say "\(%better_things capitalized) rule and \(%worse_things) drool!" I like "dogs" more than "cats" I think "chihuahuas" are worse than "corgis" @@ -190,20 +195,26 @@ I think "chihuahuas" are worse than "corgis" say both "Hello" and also "again!" # Functions can even have their name at the end: -rule [%what-she-said is what she said] =: - say %what-she-said +rule [%what_she_said is what she said] =: + say %what_she_said say "-- she said" "Howdy pardner" is what she said -#.. The language only reserves []{}().,:;% as special characters, so functions and variables +#.. The language only reserves []{}().,:;% as special characters, so functions can have really funky names! -rule [>> %foo-bar$$$^ --> %@@& _~-^-~_~-^ %1 !] =: - say %foo-bar$$$^ - say %@@& +rule [>> %foo_bar $$$^ --> %@ @& _~-^-~_~-^ %1 !] =: + say %foo_bar + say %@ say %1 ->> "wow" --> "so flexible!" _~-^-~_~-^ "even numbers can be variables!" ! +>> "wow" $$$^ --> "so flexible!" @& _~-^-~_~-^ "even numbers can be variables!" ! + +#.. The all of the following are characters won't "stick" to their neighbors, so the + compiler treats them as solitary single-character tokens: '~`!@$^&*-+=|<>?/ + which means you can jam things together: +rule [%x++%y] =: 2*(%x+%y) +(5++2) == ( 5 ++ 2 ) # Math and logic operations are just treated the same as function calls in the syntax say (2 + 3) diff --git a/examples/sample_game.nom b/examples/sample_game.nom index 3698fb4..a6a792d 100644 --- a/examples/sample_game.nom +++ b/examples/sample_game.nom @@ -30,7 +30,7 @@ with secrets: | return t; |end}); - rule [inventory] =: dict: + rule [inventory] =: dict (..) [%inv's "key", dict (%entry for %entry in (entries in (%inv's "value")))] ..for %inv in (entries in (secret %inventory)) @@ -207,16 +207,16 @@ propose: rule [vote for %candidate] =: for %c in (secret %candidates): if (%c == %candidate): - go to %candidate-is-legit + go to %candidate_is_legit error ".." |Invalid candidate: \(%candidate) - -> %candidate-is-legit + -> %candidate_is_legit (secret %votes)->(you) =: %candidate - %vote-percent = ((number of (votes for %candidate)) / (number of (everyone))) + %vote_percent = ((number of (votes for %candidate)) / (number of (everyone))) say ".." - |Vote cast. \(%candidate) now has \(100 * %vote-percent)% of the votes. - if (%vote-percent > 0.5): + |Vote cast. \(%candidate) now has \(100 * %vote_percent)% of the votes. + if (%vote_percent > 0.5): secret %winner = %candidate after winning a fair election do (secret %action) close the election diff --git a/lib/collections.nom b/lib/collections.nom index 022c1dc..5958bb9 100644 --- a/lib/collections.nom +++ b/lib/collections.nom @@ -19,7 +19,7 @@ parse [first in %list, first %list] as: 1 st in %list parse [last in %list, last %list] as: 1 st to last in %list # Dict iteration convenience function. This could also be accomplished with: for all (entries in %dict): ... -compile [for %key -> %value in %dict %body] to code: ".." +compile [for %key = %value in %dict %body] to code: ".." |do; | for k, v in pairs(\(%dict as lua)) do; | \(%key as lua), \(%value as lua) = k, v; @@ -29,7 +29,7 @@ compile [for %key -> %value in %dict %body] to code: ".." # Membership testing rule [%item is in %list, %list contains %item, %list has %item] =: - for %key -> %value in %list: + for %key = %value in %list: if (%key == %item): return (yes) return (no) @@ -38,7 +38,7 @@ rule [..] %list doesn't contain %item, %list does not contain %item %list doesn't have %item, %list does not have %item ..=: - for %key -> %value in %list: + for %key = %value in %list: if (%key == %item): return (no) return (yes) @@ -87,26 +87,53 @@ rule [flatten %lists] =: add %item to %flat %flat -rule [dict %items] =: +rule [dict from entries %items] =: %dict = [] for %pair in %items: %dict -> (%pair -> 1) = (%pair -> 2) %dict +compile [dict %items] to: + if ((%items's "type") == "Thunk"): + %item_codes = [] + for %func_call in (%items's "value"): + assert ((%func_call's "type") == "FunctionCall") ".." + |Invalid format for 'dict' expression. Only literals are allowed. + %tokens = (%func_call's "value") + %equals = (%tokens -> 2) + assert (lua expr "#\(%tokens) == 3 and \(%equals) and \(%equals).type == 'Word' and \(%equals).value == '='") ".." + |Invalid format for 'dict' expression. Lines must only have the "% = %" format, not \(%func_call's "src") + %key = (%tokens -> 1) + lua code ".." + |if \(%key).type == "Word" and \(%key).value:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then + | \(%key_code) = \(%key).value; + |elseif \(%key).type == "Word" then + | \(%key_code) = "["..nomsu:repr(\(%key).value).."]"; + |else + | \(\{%key_code = "[\((%key as lua))]"} as lua statements) + |end + add "\(%key_code) = \((%tokens -> 3) as lua)" to %item_codes + return "{\(join %item_codes with glue ",\n")}" + ..else: + return (..) + (..) + nomsu "replaced_vars" [\(dict from entries %items), lua expr "vars"] + ..as lua + rule [entries in %dict] =: %entries = [] - for %k -> %v in %dict: - add (dict [["key",%k],["value",%v]]) to %entries + for %k = %v in %dict: + add (dict {key = %k; value = %v}) to %entries %entries rule [keys in %dict] =: %keys = [] - for %k -> %v in %dict: add %k to %keys + for %k = %v in %dict: add %k to %keys %keys rule [values in %dict] =: %values = [] - for %k -> %v in %dict: add %v to %values + for %k = %v in %dict: add %v to %values %values # List Comprehension diff --git a/lib/control_flow.nom b/lib/control_flow.nom index 2c51c50..84aca6c 100644 --- a/lib/control_flow.nom +++ b/lib/control_flow.nom @@ -21,7 +21,7 @@ compile [if %condition %if_body else %else_body, unless %condition %else_body el # Return compile [return] to code: "do; return; end;" -compile [return %return-value] to code: "do; return \(%return-value as lua); end;" +compile [return %return_value] to code: "do; return \(%return_value as lua); end;" # GOTOs compile [-> %label] to code: ".." @@ -44,11 +44,11 @@ rule [tree %tree has function call %call] =: compile [do next repeat-loop] to code: "goto continue_repeat;" compile [stop repeat-loop] to code: "goto stop_repeat;" compile [repeat while %condition %body] to code: - %continue-labels = (..) + %continue_labels = (..) "\n::continue_repeat::;" if (tree %body has function call \(do next repeat-loop)) else "" %code = ".." |while \(%condition as lua) do; - |\(%body as lua statements)\(%continue-labels) + |\(%body as lua statements)\(%continue_labels) |end;--while-loop if (tree %body has function call \(stop repeat-loop)): return ".." @@ -73,25 +73,25 @@ compile [..] for %var from %start to %stop by %step %body for %var from %start to %stop via %step %body ..to code: - %continue-labels = "" + %continue_labels = "" if (tree %body has function call \(do next for-loop)): - %continue-labels join= "\n::continue_for::;" + %continue_labels join= "\n::continue_for::;" if (tree %body has function call (nomsu "replaced_vars" [\(do next %), lua expr "{['']=\(%var)}"])): - %continue-labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;" + %continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;" %code = ".." |for i=\(%start as lua),\(%stop as lua),\(%step as lua) do; # This trashes the loop variables, just like in Python. |\(%var as lua) = i; - |\(%body as lua statements)\(%continue-labels) + |\(%body as lua statements)\(%continue_labels) |end;--numeric for-loop - %stop-labels = "" + %stop_labels = "" if (tree %body has function call \(stop for-loop)): - %stop-labels join= "\n::stop_for::;" + %stop_labels join= "\n::stop_for::;" if (tree %body has function call (nomsu "replaced_vars" [\(stop %), lua expr "{['']=\(%var)}"])): - %stop-labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;" - if (%stop-labels != ""): ".." + %stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;" + if (%stop_labels != ""): ".." |do;--for-loop label scope - |\(%code)\(%stop-labels) + |\(%code)\(%stop_labels) |end;--for-loop label scope ..else: %code parse [for %var from %start to %stop %body] as: for %var from %start to %stop via 1 %body @@ -102,25 +102,25 @@ parse [..] parse [for all %start to %stop %body] as: for all %start to %stop via 1 %body compile [for %var in %iterable %body] to code: - %continue-labels = "" + %continue_labels = "" if (tree %body has function call \(do next for-loop)): - %continue-labels join= "\n::continue_for::;" + %continue_labels join= "\n::continue_for::;" if (tree %body has function call (nomsu "replaced_vars" [\(do next %), lua expr "{['']=\(%var)}"])): - %continue-labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;" + %continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;" %code = ".." |for i,value in ipairs(\(%iterable as lua)) do; # This trashes the loop variables, just like in Python. |\(%var as lua) = value; - |\(%body as lua statements)\(%continue-labels) + |\(%body as lua statements)\(%continue_labels) |end;--foreach-loop - %stop-labels = "" + %stop_labels = "" if (tree %body has function call \(stop for-loop)): - %stop-labels join= "\n::stop_for::;" + %stop_labels join= "\n::stop_for::;" if (tree %body has function call (nomsu "replaced_vars" [\(stop %), lua expr "{['']=\(%var)}"])): - %stop-labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;" - if (%stop-labels != ""): ".." + %stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;" + if (%stop_labels != ""): ".." |do;--for-loop label scope - |\(%code)\(%stop-labels) + |\(%code)\(%stop_labels) |end;--for-loop label scope ..else: %code parse [for all %iterable %body] as: for % in %iterable %body @@ -131,10 +131,10 @@ compile [when %body] to code: %result = "" %fallthroughs = [] %first = (yes) - for %func-call in (%body's "value"): - assert ((%func-call's "type") == "FunctionCall") ".." + for %func_call in (%body's "value"): + assert ((%func_call's "type") == "FunctionCall") ".." |Invalid format for 'when' statement. Only '*' blocks are allowed. - %tokens = (%func-call's "value") + %tokens = (%func_call's "value") %star = (%tokens -> 1) assert (lua expr "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".." |Invalid format for 'when' statement. Lines must begin with '*' @@ -146,7 +146,7 @@ compile [when %body] to code: %action = (%tokens -> 3) if (%action == (nil)): lua block "table.insert(vars.fallthroughs, vars.condition)" - do next %func-call + do next %func_call if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"): %result join= ".." @@ -171,14 +171,14 @@ compile [when %body] to code: %result # Switch statement -compile [when %branch-value == ? %body] to code: +compile [when %branch_value == ? %body] to code: %result = "" %fallthroughs = [] %first = (yes) - for %func-call in (%body's "value"): - assert ((%func-call's "type") == "FunctionCall") ".." + for %func_call in (%body's "value"): + assert ((%func_call's "type") == "FunctionCall") ".." |Invalid format for 'when' statement. Only '*' blocks are allowed. - %tokens = (%func-call's "value") + %tokens = (%func_call's "value") %star = (%tokens -> 1) assert (lua expr "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".." |Invalid format for 'when' statement. Lines must begin with '*' @@ -190,7 +190,7 @@ compile [when %branch-value == ? %body] to code: %action = (%tokens -> 3) if (%action == (nil)): lua block "table.insert(vars.fallthroughs, vars.condition)" - do next %func-call + do next %func_call if (lua expr "vars.condition.type == 'Word' and vars.condition.value == 'else'"): %result join= ".." @@ -213,7 +213,7 @@ compile [when %branch-value == ? %body] to code: if (%result != ""): %result = ".." |do;--when == ? - |local branch_value = \(%branch-value as lua);\(%result) + |local branch_value = \(%branch_value as lua);\(%result) |end; |end;--when == ? %result diff --git a/lib/operators.nom b/lib/operators.nom index 13e6ce4..09bdbcd 100644 --- a/lib/operators.nom +++ b/lib/operators.nom @@ -29,7 +29,7 @@ compile [..] |end)(nomsu, vars) # Indexing: -compile [%obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]" +compile [%obj'%key, %obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]" # Variable assignment operator, and += type versions compile [%var = %val] to code: "\(%var as lua) = \(%val as lua);" @@ -90,7 +90,7 @@ lua block ".." # Chained compairsions (e.g. x < y <= z) are defined up to 3 operands lua block ".." |local max_operands = 3; - |for _,chainers in ipairs({{"<","<="},{">",">="}}) do; + |for _,chainers in ipairs({{"<","< ="},{">","> ="}}) do; | local function recurse(chainers, chain) # The 1-op versions are already more efficiently defined, and a 0-op version doesnt make sense | if #chain >= 2 then; diff --git a/lib/permissions.nom b/lib/permissions.nom index 1725683..3231b25 100644 --- a/lib/permissions.nom +++ b/lib/permissions.nom @@ -15,33 +15,33 @@ rule [standardize rules %rules] =: keys in %set -rule [restrict %rules to within %elite-rules] =: +rule [restrict %rules to within %elite_rules] =: %rules = (standardize rules %rules) - %elite-rules = (standardize rules %elite-rules) - for all (flatten [%elite-rules, %rules]): + %elite_rules = (standardize rules %elite_rules) + for all (flatten [%elite_rules, %rules]): assert ((nomsu's "defs") has key %) "Undefined function: \(%)" for %rule in %rules: assert (nomsu "check_permission" [%]) ".." |You do not have permission to restrict permissions for function: \(%) ((nomsu) ->* ["defs",%rule,"whiteset"]) = (..) - dict ([%, yes] for all %elite-rules) + dict ([%, yes] for all %elite_rules) -rule [allow %elite-rules to use %rules] =: +rule [allow %elite_rules to use %rules] =: %rules = (standardize rules %rules) - %elite-rules = (standardize rules %elite-rules) - for all (flatten [%elite-rules, %rules]): + %elite_rules = (standardize rules %elite_rules) + for all (flatten [%elite_rules, %rules]): assert ((nomsu's "defs") has key %) "Undefined function: \(%)" for %rule in %rules: assert (nomsu "check_permission" [%rule]) ".." |You do not have permission to grant permissions for function: \(%rule) %whiteset = ((nomsu) ->* ["defs",%rule,"whiteset"]) if (not %whiteset): go to next %rule - for all %elite-rules: %whiteset -> % = (yes) + for all %elite_rules: %whiteset -> % = (yes) -rule [forbid %pleb-rules to use %rules] =: +rule [forbid %pleb_rules to use %rules] =: %rules = (standardize rules %rules) - %pleb-rules = (standardize rules %pleb-rules) - for all (flatten [%pleb-rules, %used]): + %pleb_rules = (standardize rules %pleb_rules) + for all (flatten [%pleb_rules, %used]): assert ((nomsu's "defs") has key %) "Undefined function: \(%)" for all %rules: assert (nomsu "check_permission" [%]) ".." @@ -50,4 +50,4 @@ rule [forbid %pleb-rules to use %rules] =: assert %whiteset ".." |Cannot individually restrict permissions for \(%) because it is currently |available to everyone. Perhaps you meant to use "restrict % to within %" instead? - for all %pleb-rules: %whiteset's % = (nil) + for all %pleb_rules: %whiteset's % = (nil) diff --git a/lib/plurals.nom b/lib/plurals.nom index 347c2e7..da0fa4d 100644 --- a/lib/plurals.nom +++ b/lib/plurals.nom @@ -29,7 +29,7 @@ with secrets: rule [plural %singular] =: %singular in (secret %plurals) - rule [canonicalize %item-name] =: - %item-name in (secret %canonicals) + rule [canonicalize %item_name] =: + %item_name in (secret %canonicals) rule [rules that change plurals] =: ["the plural of % is %"] diff --git a/nomsu.lua b/nomsu.lua index 28bb36d..cbcbf9e 100644 --- a/nomsu.lua +++ b/nomsu.lua @@ -70,7 +70,7 @@ local nomsu = [=[ file <- ({{| shebang? noeol_statement <- noeol_functioncall / noeol_expression inline_statement <- inline_functioncall / inline_expression - inline_thunk <- ({ {| "{" inline_statements "}" |} }) -> Thunk + inline_thunk <- ({ {| "{" %ws? inline_statements %ws? "}" |} }) -> Thunk eol_thunk <- ({ {| ":" %ws? noeol_statements eol |} }) -> Thunk indented_thunk <- ({ {| (":" / "{..}") indent statements (nodent statements)* @@ -82,7 +82,7 @@ local nomsu = [=[ file <- ({{| shebang? indented_nomsu <- ({("\" expression) }) -> Nomsu inline_expression <- number / variable / inline_string / inline_list / inline_nomsu - / inline_thunk / ("(" inline_statement ")") + / inline_thunk / ("(" %ws? inline_statement %ws? ")") noeol_expression <- indented_string / indented_nomsu / indented_list / indented_thunk / ("(..)" indent statement @@ -101,7 +101,7 @@ local nomsu = [=[ file <- ({{| shebang? (expression (dotdot / tok_gap))* word ((dotdot / tok_gap) (expression / word))* |} }) -> FunctionCall - word <- ({ !number {%wordchar (!"'" %wordchar)*} }) -> Word + word <- ({ { %wordbreaker / (!number %wordchar+) } }) -> Word inline_string <- ({ '"' {| ({~ (("\\" -> "\") / ('\"' -> '"') / ("\n" -> " @@ -119,7 +119,7 @@ local nomsu = [=[ file <- ({{| shebang? -- Variables can be nameless (i.e. just %) and can't contain apostrophes -- which is a hack to allow %foo's to parse as "%foo" and "'s" separately - variable <- ({ ("%" { (!"'" %wordchar)* }) }) -> Var + variable <- ({ ("%" { (%wordbreaker / (%wordchar+))? }) }) -> Var inline_list <- ({ {| ("[" %ws? ((inline_list_item comma)* inline_list_item comma?)? %ws? "]") @@ -140,22 +140,24 @@ local nomsu = [=[ file <- ({{| shebang? indent <- eol (%nl ignored_line)* %nl %indented ((block_comment/line_comment) (%nl ignored_line)* nodent)? nodent <- eol (%nl ignored_line)* %nl %nodented dedent <- eol (%nl ignored_line)* (((!.) &%dedented) / (&(%nl %dedented))) - tok_gap <- %ws / %prev_edge / &("[" / "\" / [.,:;{("#%']) + tok_gap <- %ws / %prev_edge / &("[" / "\" / [.,:;{("#%] / &%wordbreaker) comma <- %ws? "," %ws? semicolon <- %ws? ";" %ws? dotdot <- nodent ".." %ws? ]=] local CURRENT_FILE = nil local whitespace = S(" \t") ^ 1 +local wordbreaker = ("'~`!@$^&*-+=|<>?/") local defs = { ws = whitespace, nl = P("\n"), tonumber = tonumber, - wordchar = P(1) - S(' \t\n\r%#:;,.{}[]()"\\'), + wordbreaker = S(wordbreaker), + wordchar = P(1) - S(' \t\n\r%#:;,.{}[]()"\\' .. wordbreaker), indented = Cmt(S(" \t") ^ 0 * (#(P(1) - S(" \t\n") + (-P(1)))), check_indent), nodented = Cmt(S(" \t") ^ 0 * (#(P(1) - S(" \t\n") + (-P(1)))), check_nodent), dedented = Cmt(S(" \t") ^ 0 * (#(P(1) - S(" \t\n") + (-P(1)))), check_dedent), - prev_edge = B(S(" \t\n.,:;}])\"\\")), + prev_edge = B(S(" \t\n.,:;}])\"\\" .. wordbreaker)), line_no = function(src, pos) local line_no = 1 for _ in src:sub(1, pos):gmatch("\n") do @@ -704,7 +706,7 @@ end)]]):format(concat(lua_bits, "\n")) self:error("Nothing to get stub from") end if type(x) == 'string' then - local stub = x:gsub("'", " '"):gsub("%%%S+", "%%"):gsub("%s+", " ") + local stub = x:gsub("([" .. tostring(wordbreaker) .. "])", " %1 "):gsub("%%%S+", "%%"):gsub("%s+", " "):gsub("%s*$", "") local arg_names do local _accum_0 = { } diff --git a/nomsu.moon b/nomsu.moon index cd80510..82867ed 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -71,7 +71,7 @@ nomsu = [=[ noeol_statement <- noeol_functioncall / noeol_expression inline_statement <- inline_functioncall / inline_expression - inline_thunk <- ({ {| "{" inline_statements "}" |} }) -> Thunk + inline_thunk <- ({ {| "{" %ws? inline_statements %ws? "}" |} }) -> Thunk eol_thunk <- ({ {| ":" %ws? noeol_statements eol |} }) -> Thunk indented_thunk <- ({ {| (":" / "{..}") indent statements (nodent statements)* @@ -83,7 +83,7 @@ nomsu = [=[ indented_nomsu <- ({("\" expression) }) -> Nomsu inline_expression <- number / variable / inline_string / inline_list / inline_nomsu - / inline_thunk / ("(" inline_statement ")") + / inline_thunk / ("(" %ws? inline_statement %ws? ")") noeol_expression <- indented_string / indented_nomsu / indented_list / indented_thunk / ("(..)" indent statement @@ -102,7 +102,7 @@ nomsu = [=[ (expression (dotdot / tok_gap))* word ((dotdot / tok_gap) (expression / word))* |} }) -> FunctionCall - word <- ({ !number {%wordchar (!"'" %wordchar)*} }) -> Word + word <- ({ { %wordbreaker / (!number %wordchar+) } }) -> Word inline_string <- ({ '"' {| ({~ (("\\" -> "\") / ('\"' -> '"') / ("\n" -> " @@ -120,7 +120,7 @@ nomsu = [=[ -- Variables can be nameless (i.e. just %) and can't contain apostrophes -- which is a hack to allow %foo's to parse as "%foo" and "'s" separately - variable <- ({ ("%" { (!"'" %wordchar)* }) }) -> Var + variable <- ({ ("%" { (%wordbreaker / (%wordchar+))? }) }) -> Var inline_list <- ({ {| ("[" %ws? ((inline_list_item comma)* inline_list_item comma?)? %ws? "]") @@ -141,7 +141,7 @@ nomsu = [=[ indent <- eol (%nl ignored_line)* %nl %indented ((block_comment/line_comment) (%nl ignored_line)* nodent)? nodent <- eol (%nl ignored_line)* %nl %nodented dedent <- eol (%nl ignored_line)* (((!.) &%dedented) / (&(%nl %dedented))) - tok_gap <- %ws / %prev_edge / &("[" / "\" / [.,:;{("#%']) + tok_gap <- %ws / %prev_edge / &("[" / "\" / [.,:;{("#%] / &%wordbreaker) comma <- %ws? "," %ws? semicolon <- %ws? ";" %ws? dotdot <- nodent ".." %ws? @@ -149,13 +149,14 @@ nomsu = [=[ CURRENT_FILE = nil whitespace = S(" \t")^1 +wordbreaker = ("'~`!@$^&*-+=|<>?/") defs = - ws:whitespace, nl: P("\n"), :tonumber - wordchar: P(1)-S(' \t\n\r%#:;,.{}[]()"\\') + ws:whitespace, nl: P("\n"), :tonumber, wordbreaker:S(wordbreaker) + wordchar: P(1)-S(' \t\n\r%#:;,.{}[]()"\\'..wordbreaker) indented: Cmt(S(" \t")^0 * (#(P(1)-S(" \t\n") + (-P(1)))), check_indent) nodented: Cmt(S(" \t")^0 * (#(P(1)-S(" \t\n") + (-P(1)))), check_nodent) dedented: Cmt(S(" \t")^0 * (#(P(1)-S(" \t\n") + (-P(1)))), check_dedent) - prev_edge: B(S(" \t\n.,:;}])\"\\")) + prev_edge: B(S(" \t\n.,:;}])\"\\"..wordbreaker)) line_no: (src, pos)-> line_no = 1 for _ in src\sub(1,pos)\gmatch("\n") do line_no += 1 @@ -541,7 +542,7 @@ end)]])\format(concat(lua_bits, "\n")) -- Returns a single stub ("say %"), and list of arg names ({"msg"}) from a single rule def -- (e.g. "say %msg") or function call (e.g. FunctionCall({Word("say"), Var("msg"))) if type(x) == 'string' - stub = x\gsub("'"," '")\gsub("%%%S+","%%")\gsub("%s+"," ") + stub = x\gsub("([#{wordbreaker}])"," %1 ")\gsub("%%%S+","%%")\gsub("%s+"," ")\gsub("%s*$","") arg_names = [arg for arg in x\gmatch("%%([^%s']*)")] return stub, arg_names switch x.type