From f746ba34d799e6560df1aad1cad15a70b34914d1 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 22 Jan 2019 16:15:25 -0800 Subject: Moved all the text method stuff into text.moon instead of splitting across string2/containers. Modified the type stuff to output better type names and use (a Dict) and (a List) instead of (Dict) and (List). (Text) now also has a proper constructor. (assume) now also handles a bunch of different assumptions with smart error messages. --- lib/compatibility/compatibility.nom | 2 +- lib/core/control_flow.nom | 2 +- lib/core/errors.nom | 84 ++++++++++++++++++++++++++----------- lib/core/metaprogramming.nom | 36 ++++++++-------- lib/core/text.nom | 2 +- lib/tools/tutorial.nom | 83 ++++++++++++++++++------------------ 6 files changed, 122 insertions(+), 87 deletions(-) mode change 100644 => 100755 lib/tools/tutorial.nom (limited to 'lib') diff --git a/lib/compatibility/compatibility.nom b/lib/compatibility/compatibility.nom index 45ea1d6..b72997e 100644 --- a/lib/compatibility/compatibility.nom +++ b/lib/compatibility/compatibility.nom @@ -43,7 +43,7 @@ external: ($t is syntax tree): $args = [] for $k = $v in $t: - if ((type of $k) == "a number"): + if ((type of $k) == "a Number"): $args, add (make tree $v) ..else: $args, add "\($k)=\(make tree $v)" diff --git a/lib/core/control_flow.nom b/lib/core/control_flow.nom index 2ad7ec7..bf044d9 100644 --- a/lib/core/control_flow.nom +++ b/lib/core/control_flow.nom @@ -485,7 +485,7 @@ test: $lua = Lua (" do - local _stack_\($var as lua expr) = List{\($structure as lua expr)} + local _stack_\($var as lua expr) = a_List{\($structure as lua expr)} while #_stack_\($var as lua expr) > 0 do \($var as lua expr) = table.remove(_stack_\($var as lua expr), 1) \($body as lua) diff --git a/lib/core/errors.nom b/lib/core/errors.nom index a84b580..e24c012 100644 --- a/lib/core/errors.nom +++ b/lib/core/errors.nom @@ -14,31 +14,67 @@ use "core/control_flow" )) ") -(assume $condition) compiles to (" - if not \($condition as lua expr) then - at_1_fail(\(quote "\($condition.source)"), "Assumption failed: This was not true.") - end -") - -(assume $a == $b) compiles to (" - do - local _a, _b = \($a as lua expr), \($b as lua expr) - if _a ~= _b then - at_1_fail(\(quote "\($a.source)"), - "Assumption failed: This value was "..tostring(_a).." but it was expected to be "..tostring(_b)..".") - end - end -") +(assume $condition) compiles to: + if ($condition.type == "Action"): + when $condition.stub is: + "1 ==": + return + LuaCode (" + do + local _a, _b = \($condition.1 as lua expr), \($condition.3 as lua expr) + if _a ~= _b then + _a = type_of(_a) == 'Text' and _a:as_lua() or tostring(_a) + _b = type_of(_b) == 'Text' and _b:as_lua() or tostring(_b) + at_1_fail(\(quote "\($condition.1.source)"), + "Assumption failed: This value was ".._a.." but it was expected to be ".._b..".") + end + end + ") + "1 !=": + return + LuaCode (" + do + local _a, _b = \($condition.1 as lua expr), \($condition.3 as lua expr) + if _a == _b then + _a = type_of(_a) == 'Text' and _a:as_lua() or tostring(_a) + at_1_fail(\(quote "\($condition.1.source)"), + "Assumption failed: This value was ".._a.." but it wasn't expected to be.") + end + end + ") + "1 >" "1 <" "1 >=" "1 <=": + return + LuaCode (" + do + local _a, _b = \($condition.1 as lua expr), \($condition.3 as lua expr) + if _a ~= _b then + _a = type_of(_a) == 'Text' and _a:as_lua() or tostring(_a) + _b = type_of(_b) == 'Text' and _b:as_lua() or tostring(_b) + at_1_fail(\(quote "\($condition.1.source)"), + "Assumption failed: This value was ".._a..", but it was expected to be \($condition.3)".._b..".") + end + end + ") + "1 is": + return + LuaCode (" + do + local _ta, _tb = type_of(\($condition.1 as lua expr)), \($condition.3 as lua expr) + if _ta ~= _tb then + at_1_fail(\(quote "\($condition.1.source)"), + "Assumption failed: This value was ".._ta.." but it was expected to be ".._tb..".") + end + end + ") + return + LuaCode (" + if not \($condition as lua expr) then + at_1_fail(\(quote "\($condition.source)"), "Assumption failed: This assumption did not hold.") + end + ") -(assume $a != $b) compiles to (" - do - local _a, _b = \($a as lua expr), \($b as lua expr) - if _a == _b then - at_1_fail(\(quote "\($a.source)"), - "Assumption failed: This value was "..tostring(_a).." but it wasn't expected to be.") - end - end -") +(assume $a == $b) parses as (assume ($a == $b)) +(assume $a != $b) parses as (assume ($a != $b)) test: try: fail diff --git a/lib/core/metaprogramming.nom b/lib/core/metaprogramming.nom index bfcc0bf..c7d3787 100644 --- a/lib/core/metaprogramming.nom +++ b/lib/core/metaprogramming.nom @@ -26,7 +26,8 @@ lua> (" lua> (" COMPILE_RULES["1 ->"] = function(\(nomsu environment), _tree, \$args, \$body) - if \$args and not \$body then \$args, \$body = {}, \$args end + if not \$args and not \$body then \$args, \$body = {}, SyntaxTree{type='Action', "do", "nothing"} + elseif \$args and not \$body then \$args, \$body = {}, \$args end local body_lua = SyntaxTree:is_instance(\$body) and \(nomsu environment):compile(\$body) or \$body if SyntaxTree:is_instance(\$body) and \$body.type ~= "Block" then body_lua:prepend("return ") end local lua = LuaCode("(function(") @@ -88,7 +89,7 @@ test: lua> (" COMPILE_RULES["1 compiles to"] = function(\(nomsu environment), \(this tree), \$action, \$body) - local \$args = List{"\(nomsu environment)", "\(this tree)"} + local \$args = a_List{"\(nomsu environment)", "\(this tree)"} if \$body.type == "Text" then \$body = SyntaxTree{source=\$body.source, type="Action", "Lua", \$body} end @@ -121,18 +122,18 @@ lua> (" at_1_fail(\$actions, "Compile error: This should be a list of actions.") end local lua = \(\($actions.1 compiles to $body) as lua) - local \$args = List{"\(nomsu environment)", "\(this tree)", unpack(\$actions[1]:get_args())} - local \$compiled_args = List{"\(nomsu environment)", "\(this tree)"}; + local \$args = a_List{"\(nomsu environment)", "\(this tree)", unpack(\$actions[1]:get_args())} + local \$compiled_args = a_List{"\(nomsu environment)", "\(this tree)"}; for i=3,#\$args do \$compiled_args[i] = \(nomsu environment):compile(\$args[i]) end for i=2,#\$actions do local alias = \$actions[i] - local \$alias_args = List{"\(nomsu environment)", "\(this tree)", unpack(alias:get_args())} + local \$alias_args = a_List{"\(nomsu environment)", "\(this tree)", unpack(alias:get_args())} lua:add("\\nCOMPILE_RULES[", alias:get_stub():as_lua(), "] = ") if \$alias_args == \$args then lua:add("COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "]") else lua:add("function(") - local \$compiled_alias_args = List{"\(nomsu environment)", "\(this tree)"}; + local \$compiled_alias_args = a_List{"\(nomsu environment)", "\(this tree)"}; for i=3,#\$alias_args do \$compiled_alias_args[i] = \(nomsu environment):compile(\$alias_args[i]) end lua:concat_add(\$compiled_alias_args, ", ") lua:add(") return COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "](") @@ -183,10 +184,10 @@ test: local first_def = (\$actions[1].type == "MethodCall" and LuaCode(\(nomsu environment):compile(\$actions[1][1]), ".", \$actions[1]:get_stub():as_lua_id()) or LuaCode(\$actions[1]:get_stub():as_lua_id())) - local \$args = List(\$actions[1]:get_args()) + local \$args = a_List(\$actions[1]:get_args()) for i=2,#\$actions do local alias = \$actions[i] - local \$alias_args = List(alias:get_args()) + local \$alias_args = a_List(alias:get_args()) lua:add("\\n") if alias.type == "MethodCall" then lua:add(\(nomsu environment):compile(alias[1]), ".", alias:get_stub():as_lua_id()) @@ -392,10 +393,10 @@ external: external: (match $tree with $patt) means: lua> (" - if \$patt.type == "Var" then return Dict{[\$patt:as_var()]=\$tree} end + if \$patt.type == "Var" then return a_Dict{[\$patt:as_var()]=\$tree} end if \$patt.type == "Action" and \$patt:get_stub() ~= \$tree:get_stub() then return nil end if #\$patt ~= #\$tree then return nil end - local matches = Dict{} + local matches = a_Dict{} for \($i)=1,#\$patt do if SyntaxTree:is_instance(\$tree[\$i]) then local submatch = \(match $tree.$i with $patt.$i) @@ -425,6 +426,9 @@ test: assume ({} is "a Dict") assume ("" is text) assume ("" is "Text") + assume (5 is "a Number") + assume ((->) is "an Action") + assume ((yes) is "a Boolean") assume ("" isn't "a Dict") external: @@ -432,14 +436,12 @@ external: [$ is not text, $ isn't text] all mean (=lua "\(lua type of $) ~= 'string'") (type of $) means: lua> (" + local mt = getmetatable(\$) + if mt and mt.__type then return mt.__type end + if \$ == nil then return 'nil' end local lua_type = \(lua type of $) - if lua_type == 'string' then return 'Text' - elseif lua_type == 'nil' then return 'nil' - elseif lua_type == 'table' or lua_type == 'userdata' then - local mt = getmetatable(\$) - if mt and mt.__type then return mt.__type end - end - return 'a '..lua_type + if lua_type == 'function' then return "an Action" end + return 'a '..lua_type:capitalized() ") ($ is $type) parses as ((type of $) == $type) diff --git a/lib/core/text.nom b/lib/core/text.nom index a1fcaae..1401cf2 100644 --- a/lib/core/text.nom +++ b/lib/core/text.nom @@ -46,7 +46,7 @@ test: return Lua (" (function() - local \(mangle "comprehension") = List{} + local \(mangle "comprehension") = a_List{} for \($match as lua expr) in (\($text as lua expr)):gmatch(\($patt as lua expr)) do \(mangle "comprehension")[#\(mangle "comprehension")+1] = \($expr as lua) end diff --git a/lib/tools/tutorial.nom b/lib/tools/tutorial.nom old mode 100644 new mode 100755 index e8295c2..3cdb10c --- a/lib/tools/tutorial.nom +++ b/lib/tools/tutorial.nom @@ -26,10 +26,10 @@ $lessons = [ # In Nomsu, variables have a "$" prefix, and you can just assign to them without declaring them first: $x = 10 - assume $x == 10 + assume ($x == 10) # Variables which have not yet been set have the value (nil) - assume $foobar == (nil) + assume ($foobar == (nil)) # Variables can be nameless: $ = 99 @@ -40,7 +40,7 @@ $lessons = [ # Figure out what value $my_var should have: $my_var = 100 $my_var = ($my_var + $x + $(my favorite number)) - assume (???) == $my_var + assume ($my_var == (???)) lesson "Actions": # Fix this action so the tests pass, then save and quit. @@ -48,8 +48,8 @@ $lessons = [ ($x doubled) means ((???) * $x) # Tests: - assume (2 doubled) == 4 - assume (-5 doubled) == -10 + assume ((2 doubled) == 4) + assume ((-5 doubled) == -10) lesson "Blocks": # When you need to do multiple things inside an action, use a block. @@ -69,17 +69,17 @@ $lessons = [ # Make this action return "big" if its argument # is bigger than 99, otherwise return "small" (the size of $n) means: - if (): + if (???): ..else: # Tests: for $small_number in [0, 1, -5, -999, 99]: - assume (the size of $small_number) == "small" + assume ((the size of $small_number) == "small") for $big_number in [9999, 100]: - assume (the size of $big_number) == "big" + assume ((the size of $big_number) == "big") lesson "Loops": # Fix this action so the tests pass: @@ -92,14 +92,14 @@ $lessons = [ return $sum # Tests: - assume (the sum of [1, 2, 3, 4, 5]) == 15 - assume (the sum of [100, 200]) == 300 + assume ((the sum of [1, 2, 3, 4, 5]) == 15) + assume ((the sum of [100, 200]) == 300) # You can also loop over a number range like this: $total = 0 for $i in 1 to 3: $total = ($total + $i) - assume (???) == $total + assume ($total == (???)) lesson "Variable Scopes": # Nomsu's variables are local by default, and actions have their own scopes: @@ -110,17 +110,17 @@ $lessons = [ (do something) means: # The variable $y is never set in this action, so it has the same value it has outside this action. - assume (???) == $y + assume ($y == (???)) # $x is set inside this action, and actions have their own scopes. $x = $y # What number should $x be here? - assume (???) == $x + assume ($x == (???)) # After running the action, what value should $x have? do something - assume (???) == $x + assume ($x == (???)) lesson "More Variable Scopes": # Loops and conditionals do *not* have their own scopes: @@ -130,13 +130,13 @@ $lessons = [ $z = 2 # After assigning in a conditional, what should $z be? - assume (???) == $z + assume ($z == (???)) for $ in 1 to 1: # Set $z inside a loop: $z = 3 # After assigning in a loop, what should $z be? - assume (???) == $z + assume ($z == (???)) lesson "Externals": # The 'external' block lets you modify variables outside an action: @@ -146,7 +146,7 @@ $lessons = [ do something # After running the action that sets $x in an 'external' block, what should $x be? - assume (???) == $x + assume ($x == (???)) lesson "Locals": # The 'with' block lets you create a local scope for the variables you list: @@ -157,8 +157,8 @@ $lessons = [ $z = 2 # After setting $y and $z in the 'with [$y]' block, what should $y and $z be? - assume (???) == $y - assume (???) == $z + assume ($y == (???)) + assume ($z == (???)) lesson "Failure and Recovery": $what_happened = "nothing" @@ -172,7 +172,7 @@ $lessons = [ $what_happened = "success" # What do you think happened? - assume (???) == $what_happened + assume ($what_happened == (???)) # Note: a 'try' block will silence failures, so this has no effect: try: fail @@ -180,11 +180,11 @@ $lessons = [ lesson "Indexing": # Nomsu uses the "." operator to access things inside an object: $dictionary = {.dog = "A lovable doofus", .cat = "An internet superstar"} - assume $dictionary.dog == "A lovable doofus" - assume (???) == $dictionary.cat + assume ($dictionary.dog == "A lovable doofus") + assume ($dictionary.cat == (???)) # If you try to access a key that's not in an object, the result is (nil): - assume (???) == $dictionary.mimsy + assume ($dictionary.mimsy == (???)) # $dictionary.dog is just a shorthand for $dictionary."dog". You may need to use the longer form for strings with spaces: @@ -195,22 +195,22 @@ $lessons = [ $dictionary.5 = "The number five" $dictionary.five = 5 $dictionary.myself = $dictionary - assume (???) == $dictionary.myself + assume ($dictionary.myself == (???)) # Lists are similar, but use square brackets ([]) and can only have numbers as keys, starting at 1: $list = ["first", "second", 999] - assume $list.1 == "first" - assume (???) == $list.2 - assume (???) == $list.3 + assume ($list.1 == "first") + assume ($list.2 == (???)) + assume ($list.3 == (???)) # Hint: 4 should be a missing key - assume (???) == $list.4 - assume (???) == $list.foobar + assume ($list.4 == (???)) + assume ($list.foobar == (???)) # The "#" action gets the number of items inside something: - assume (???) == (#$list) - assume (???) == (#{.x = 10, .y = 20}) + assume ((#$list) == (???)) + assume ((#{.x = 10, .y = 20}) == (???)) lesson "Methods": # The "," is used for method calls, which means calling an action @@ -218,17 +218,17 @@ $lessons = [ # Lists have an "add" method that puts new items at the end: $list = [-4, -6, 5] $list, add 3 - assume $list == [-4, -6, 5, 3] + assume ($list == [-4, -6, 5, 3]) $list, add 7 - assume $list == [???] + assume ($list == [???]) # Text also has some methods like: $name = "Harry Tuttle" - assume ($name, character 7) == "T" - assume (???) == ($name, with "Tuttle" -> "Buttle") + assume (($name, character 7) == "T") + assume (($name, with "Tuttle" -> "Buttle") == (???)) # Methods can be chained too: - assume (???) == ($name, with "Tuttle" -> "Buttle", character 7) + assume (($name, with "Tuttle" -> "Buttle", character 7) == (???)) lesson "Object Oriented Programming": # Object Oriented Programming deals with things that have @@ -244,17 +244,14 @@ $lessons = [ ($self, add $bit) means: $bits, add $bit - ($self, length) means: - # Write some code that returns the total length of all - the bits on this buffer. - # Hint: the length operator (#$foo) works on text - + # Write a method called ($self, length) that returns the total + length of all the bits in the buffer: + $b = (a Buffer) $b, add "xx" $b, add "yyy" - assume ($b, length) == 5 - assume ($b, joined) == "xxyyy" + assume (($b, length) == 5) ] command line program with $args: -- cgit v1.2.3