diff --git a/code_obj.lua b/code_obj.lua index 37ac55a..b67e78d 100644 --- a/code_obj.lua +++ b/code_obj.lua @@ -312,12 +312,6 @@ do end return statements end, - as_expr = function(self) - if self.is_value then - return self - end - return error("Cannot convert to expression: " .. tostring(tostring(self))) - end, __tostring = function(self) if self.__str == nil then local buff, indent = { }, 0 diff --git a/code_obj.moon b/code_obj.moon index e1cf226..9bfa9a5 100644 --- a/code_obj.moon +++ b/code_obj.moon @@ -4,7 +4,6 @@ {:insert, :remove, :concat} = table {:repr} = require 'utils' local LuaCode, NomsuCode, Source -export LINE_STARTS class Source new: (@filename, @start, @stop)=> @@ -185,11 +184,6 @@ class LuaCode extends Code if suffix != "" statements\append suffix return statements - - as_expr: => - if @is_value - return self - error("Cannot convert to expression: #{tostring self}") __tostring: => if @__str == nil diff --git a/compatibility/2.nom b/compatibility/2.nom index 35ed1a0..a93730c 100644 --- a/compatibility/2.nom +++ b/compatibility/2.nom @@ -4,7 +4,7 @@ use "compatibility/compatibility.nom" upgrade %tree to "2" as: unless (%tree is "Action" syntax tree): return - if (all[%tree.stub is "if % % else %", not (%tree.3 is "Var" syntax tree), not (%tree.5 is "Var" syntax tree)]): + if (%tree.stub is "if % % else %"): %true_body = (%tree.3 upgraded) unless (%true_body is "Block" syntax tree): %true_body = (=lua "Block(\%true_body.source, \%true_body)") @@ -22,7 +22,7 @@ upgrade %tree to "2" as: "for % in % to % via % %", "for % in % to % %", "for % % in % %", "do %" "for % in recursive % %", "test %", "with % %", "result of %" for %n in %need_blocks: - if ((%tree.stub is %n) and (not ((last in %tree) is "Var" syntax tree))): + if (%tree.stub is %n): %bits = (((% upgraded) if (% is syntax tree) else %) for % in %tree) unless ((last in %bits) is "Block" syntax tree): %body = (last in %bits) diff --git a/compatibility/compatibility.nom b/compatibility/compatibility.nom index 9482e32..c5ac55f 100644 --- a/compatibility/compatibility.nom +++ b/compatibility/compatibility.nom @@ -21,16 +21,16 @@ compile [upgrade action %action to %version as %body] to: %replacements.(%action.%i.1) = "\(\%tree as lua id)[\%i]" local action [make tree %t]: when: - * (%t is "Var" syntax tree): + (%t is "Var" syntax tree): if (%replacements.(%t.1)): return %replacements.(%t.1) ..else: return "\(%t.type)(\(quote "\(%t.source)"), \(quote "\(%t.1) \0\(=lua "string.format('%X', __MANGLE_INDEX)")"))" - * (%t is syntax tree): + (%t is syntax tree): %args = ((make tree %) for % in %t) add "\(\%tree as lua id).source" to %args at index 1 return "\(%t.type)(\(%args joined with ", "))" - *else: return (quote "\%t") + else: return (quote "\%t") return (..) Lua ".." A_upgrade_action_1_to_2_via_3(\(quote %action.stub), \(%version as lua expr), function(\(\%tree as lua id)) @@ -66,9 +66,9 @@ parse [%tree upgraded from %start_version] as (..) %tree upgraded from %start_version to (Nomsu version) parse [%tree upgraded to %end_version] as (..) - %tree upgraded from %tree.version to %end_version + %tree upgraded from (%tree.version or "0") to %end_version -parse [%tree upgraded] as (%tree upgraded from %tree.version to (Nomsu version)) +parse [%tree upgraded] as (%tree upgraded from (%tree.version or "0") to (Nomsu version)) action [use %path from version %version] (..) for file %filename in %path: if (=lua "LOADED[\%filename]"): do next %filename diff --git a/core/collections.nom b/core/collections.nom index 45ca74c..428ed4d 100644 --- a/core/collections.nom +++ b/core/collections.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file contains code that supports manipulating and using collections like lists and dictionaries. diff --git a/core/control_flow.nom b/core/control_flow.nom index b3f0978..5719d72 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -154,7 +154,7 @@ compile [..] ..to: # This uses Lua's approach of only allowing loop-scoped variables in a loop - assume (%var.type is "Var") or barf "Loop expected variable, not: \%var" + unless (%var.type is "Var"): compile error at %var.source "Loop expected variable, not: %s" %lua = (..) Lua ".." for \(%var as lua expr)=\(%start as lua expr),\(%stop as lua expr),\(%step as lua expr) do @@ -185,12 +185,11 @@ compile [..] parse [for %var in %start to %stop %body] as (..) for %var in %start to %stop via 1 %body - # For-each loop (lua's "ipairs()") compile [for %var in %iterable %body] to: # This uses Lua's approach of only allowing loop-scoped variables in a loop - assume (%var.type is "Var") or barf "Loop expected variable, not: \%var" + unless (%var.type is "Var"): compile error at %var.source "Loop expected variable, not: %s" %lua = (..) Lua ".." for i,\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do @@ -223,8 +222,8 @@ compile [for %key = %value in %iterable %body, for %key %value in %iterable %bod ..to: # This uses Lua's approach of only allowing loop-scoped variables in a loop - assume (%key.type is "Var") or barf "Loop expected variable, not: \%key" - assume (%value.type is "Var") or barf "Loop expected variable, not: \%value" + unless (%key.type is "Var"): compile error at %key.source "Loop expected variable, not: %s" + unless (%value.type is "Var"): compile error at %value.source "Loop expected variable, not: %s" %lua = (..) Lua ".." for \(%key as lua identifier),\(%value as lua identifier) in pairs(\(%iterable as lua expr)) do @@ -266,101 +265,88 @@ compile [for %key = %value in %iterable %body, for %key %value in %iterable %bod ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -# Switch statement/multi-branch if -compile [when %body] to: +# Multi-branch conditional (if..elseif..else) +compile [if %body, when %body] to: %code = (Lua "") - %fallthroughs = [] - %is_first = (yes) - %seen_else = (no) - %branches = (%body if (%body.type == "Block") else [%body]) - for %func_call in %branches: - assume (%func_call.type is "Action") or barf "Invalid format for 'when' statement. Only '*' blocks are allowed." - with {%star: %func_call.1, %condition: %func_call.2, %action: %func_call.3}: - assume (%star == "*") or barf "Invalid format for 'when' statement. Lines must begin with '*'" - assume %condition or barf ".." - Invalid format for 'when' statement. Lines must begin with '*' and have a condition \ - ..or the word "else" - - if (%action is (nil)): - lua> "table.insert(\%fallthroughs, \(%condition as lua expr))" - do next %func_call - - if (%condition == "else"): - assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block" - to %code write "\nelse\n " - to %code write (%action as lua statements) - %seen_else = (yes) - ..else: - assume (not %seen_else) or barf "'else' clause needs to be last in 'when' block" - lua> "table.insert(\%fallthroughs, \(%condition as lua expr))" - to %code write "\("if" if %is_first else "\nelseif") " - for %i = %condition in %fallthroughs: - if (%i > 1): to %code write " or " - to %code write %condition - - to %code write " then\n " - to %code write (%action as lua statements) - - %fallthroughs = [] - %is_first = (no) + %clause = "if" + %else_allowed = (yes) + unless (%body.type is "Block"): compile error at %body.source "'if' expected a Block, but got: %s" + for %line in %body: + unless (..) + ((%line.type is "Action") and ((length of %line) >= 2)) + ..and (%line.(length of %line) is "Block" syntax tree) + ..: + compile error at %line.source ".." + Invalid line for 'if', each line should contain conditional expressions \ + ..followed by a block, or "else" followed by a block: + %s + %action = %line.(length of %line) + if ((%line.1 is "else") and ((length of %line) == 2)): + unless %else_allowed: compile error at %line.source "Can't have two 'else' blocks" + unless ((length of "\%code") > 0): + compile error at %line.source "Can't have an 'else' block without a preceeding condition" + to %code write "\nelse\n \(%action as lua statements)" + %else_allowed = (no) + ..else: + to %code write "\%clause " + for %i in 1 to ((length of %line) - 1): + unless (%line.%i is syntax tree): + compile error at %line.source ".." + Invalid condition for 'if' statement: + %s + if (%i > 1): to %code write " or " + to %code write (%line.%i as lua expr) + to %code write " then\n \(%action as lua statements)" + %clause = "\nelseif" - assume (%fallthroughs == []) or barf "Unfinished fallthrough conditions in 'when' block" - assume ((length of "\%code") > 0) or barf "Empty body for 'when' block" + if ((length of "\%code") == 0): + compile error at %body.source "'if' block has an empty body" to %code write "\nend --when" return %code - # Switch statement -compile [when %branch_value = ? %body, when %branch_value is? %body] to: +compile [if %branch_value is %body, when %branch_value is %body] to: %code = (Lua "") - %fallthroughs = [] - %is_first = (yes) - %seen_else = (no) - %branches = (%body if (%body.type == "Block") else [%body]) - for %func_call in %branches: - assume (%func_call.type is "Action") or barf "Invalid format for 'when' statement. Only '*' blocks are allowed." - with {%star: %func_call.1, %condition: %func_call.2, %action: %func_call.3}: - assume (%star == "*") or barf "Invalid format for 'when' statement. Lines must begin with '*'" - assume %condition or barf ".." - Invalid format for 'when' statement. Lines must begin with '*' and have a condition \ - ..or the word "else" - - if (%action is (nil)): - lua> "table.insert(\%fallthroughs, \(%condition as lua expr))" - do next %func_call - - if (%condition == "else"): - assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block" - to %code write "\nelse\n " - to %code write (%action as lua statements) - ..else: - assume (not %seen_else) or barf "'else' clause needs to be last in 'when % = ?' block" - to %code write "\("if" if %is_first else "\nelseif") " - lua> "table.insert(\%fallthroughs, \(%condition as lua expr))" - for %i = % in %fallthroughs: - if (%i > 1): to %code write " or " - if ((%.type is "Text") or (%.type is "Number")): - to %code write "branch_value == \%" - ..else: to %code write "utils.equivalent(branch_value, \%)" - - to %code write "then\n " - to %code write (%action as lua statements) - - %fallthroughs = [] - %is_first = (no) + %clause = "if" + %else_allowed = (yes) + unless (%body.type is "Block"): compile error at %body.source "'if' expected a Block, but got: %s" + for %line in %body: + unless (..) + ((%line.type is "Action") and ((length of %line) >= 2)) + ..and (%line.(length of %line) is "Block" syntax tree) + ..: + compile error at %line.source ".." + Invalid line for 'if % is % %', each line should contain expressions \ + ..followed by a block, or "else" followed by a block: + %s + %action = %line.(length of %line) + if ((%line.1 is "else") and ((length of %line) == 2)): + unless %else_allowed: compile error at %line.source "Can't have two 'else' blocks" + unless ((length of "\%code") > 0): + compile error at %line.source "Can't have an 'else' block without a preceeding condition" + to %code write "\nelse\n \(%action as lua statements)" + %else_allowed = (no) + ..else: + to %code write "\%clause " + for %i in 1 to ((length of %line) - 1): + unless (%line.%i is syntax tree): + compile error at %line.source ".." + Invalid condition for 'if' statement: + %s + if (%i > 1): to %code write " or " + to %code write "branch_value == \(%line.%i as lua expr)" + to %code write " then\n \(%action as lua statements)" + %clause = "\nelseif" - assume (%fallthroughs == []) or barf "Unfinished fallthrough conditions in 'when' block" - assume ((length of "\%code") > 0) or barf "No body for 'when % = ?' block!" - to %code write "\nend" - %code = (..) + if ((length of "\%code") == 0): + compile error at %body.source "'if % is % %' block has an empty body" + to %code write "\nend --when" + return (..) Lua ".." - do --when % = ? + do --if % is local branch_value = \(%branch_value as lua expr) \%code - end --when % = ? - - return %code - + end --if % is # Do/finally compile [do %action] to (..) diff --git a/core/coroutines.nom b/core/coroutines.nom index 54889d4..bff115d 100644 --- a/core/coroutines.nom +++ b/core/coroutines.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file defines the code that creates and manipulates coroutines diff --git a/core/errors.nom b/core/errors.nom index efa69a8..5dfed1e 100644 --- a/core/errors.nom +++ b/core/errors.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file contains basic error reporting code @@ -7,6 +7,9 @@ compile [traceback] to (Lua value "debug.traceback()") compile [traceback %] to (Lua value "debug.traceback('', \(% as lua expr))") compile [barf] to (Lua "error(nil, 0);") compile [barf %msg] to (Lua "error(\(%msg as lua expr), 0);") +compile [compile error at %source %msg] to (..) + Lua "nomsu:compile_error(\(%source as lua expr), \(%msg as lua expr))" + compile [assume %condition] to: lua> ".." local \%assumption = 'Assumption failed: '..tostring(nomsu:tree_to_nomsu(\%condition)) diff --git a/core/io.nom b/core/io.nom index 2659b3b..b06ebb3 100644 --- a/core/io.nom +++ b/core/io.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file contains basic input/output code diff --git a/core/math.nom b/core/math.nom index d8952f6..e0c58a3 100644 --- a/core/math.nom +++ b/core/math.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file defines some common math literals and functions diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 8328d26..028a914 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -1,9 +1,9 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This File contains actions for making actions and compile-time actions and some helper functions to make that easier. -lua> "NOMSU_CORE_VERSION = 3" +lua> "NOMSU_CORE_VERSION = 4" lua> ".." nomsu.COMPILE_ACTIONS["% -> %"] = function(nomsu, tree, \%args, \%body) local lua = LuaCode.Value(tree.source, "function(") @@ -119,8 +119,16 @@ compile [parse %actions as %body] to (..) local ret = \(compile as (compile %actions to %new_body)) return ret -compile [%tree as lua expr] to (..) - Lua value "nomsu:compile(\(=lua "nomsu:compile(\%tree):as_expr()")):as_expr()" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +action [%tree as lua expr]: + lua> ".." + \%tree_lua = nomsu:compile(\%tree) + if not \%tree_lua.is_value then + nomsu:compile_error(\%tree.source, "Could not convert %s to a Lua expression", + nomsu:tree_to_nomsu(\%tree)) + end + return \%tree_lua ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/core/operators.nom b/core/operators.nom index 70b0207..bce91c4 100644 --- a/core/operators.nom +++ b/core/operators.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file contains definitions of operators like "+" and "and". @@ -147,21 +147,29 @@ compile [%x wrapped around %y, %x mod %y] to (..) # (uses a lambda to avoid re-evaluating middle value, while still being an expression) parse [%x < %y < %z] as (..) =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)" + parse [%x <= %y < %z] as (..) =lua "(function(x,y,z) return x <= y and y < z; end)(\%x,\%y,\%z)" + parse [%x < %y <= %z] as (..) =lua "(function(x,y,z) return x < y and y <= z; end)(\%x,\%y,\%z)" + parse [%x <= %y <= %z] as (..) =lua "(function(x,y,z) return x <= y and y <= z; end)(\%x,\%y,\%z)" + parse [%x > %y > %z] as (..) =lua "(function(x,y,z) return x > y and y > z; end)(\%x,\%y,\%z)" + parse [%x >= %y > %z] as (..) =lua "(function(x,y,z) return x >= y and y > z; end)(\%x,\%y,\%z)" + parse [%x > %y >= %z] as (..) =lua "(function(x,y,z) return x > y and y >= z; end)(\%x,\%y,\%z)" + parse [%x >= %y >= %z] as (..) =lua "(function(x,y,z) return x >= y and y >= z; end)(\%x,\%y,\%z)" + # TODO: optimize for common case where x,y,z are all either variables or number literals # Boolean Operators compile [%x and %y] to (Lua value "(\(%x as lua expr) and \(%y as lua expr))") @@ -204,4 +212,4 @@ parse [%var /= %] as (%var = (%var / %)) parse [%var ^= %] as (%var = (%var ^ %)) parse [%var and= %] as (%var = (%var and %)) parse [%var or= %] as (%var = (%var or %)) -parse [wrap %var around %] as (%var = (%var wrapped around %)) +parse [wrap %var around %] as (%var = (%var wrapped around %)) \ No newline at end of file diff --git a/core/scopes.nom b/core/scopes.nom index 2be24e6..30bdea0 100644 --- a/core/scopes.nom +++ b/core/scopes.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file contains definitions pertaining to variable scoping @@ -8,17 +8,16 @@ use "core/collections.nom" use "core/control_flow.nom" compile [with local %locals %body, with local %locals do %body] to: %body_lua = (%body as lua statements) - when %locals.type = ?: - * "Dict": + if %locals.type is: + "Dict": %body_lua = (..) Lua "\(compile as (<- %locals))\n\%body_lua" declare locals ("\(%.1 as lua)" for % in %locals) in %body_lua - * "List": declare locals ("\(% as lua)" for % in %locals) in %body_lua - * "Var" - * "Action": declare locals ["\(%locals as lua)"] in %body_lua - *else (barf "Unexpected local: \(%locals as nomsu)") + "List": declare locals ("\(% as lua)" for % in %locals) in %body_lua + "Var" "Action": declare locals ["\(%locals as lua)"] in %body_lua + else: compile error at %locals.source "Unexpected locals: %s" return (..) Lua "do\n \%body_lua\nend" \ No newline at end of file diff --git a/core/text.nom b/core/text.nom index 62ec056..30eab50 100644 --- a/core/text.nom +++ b/core/text.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file contains some definitions of text escape sequences, including ANSI console color codes. diff --git a/lib/consolecolor.nom b/lib/consolecolor.nom index 39bae68..6e327ff 100644 --- a/lib/consolecolor.nom +++ b/lib/consolecolor.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file defines actions for ANSI console color escape codes. diff --git a/lib/file_hash.nom b/lib/file_hash.nom index 283c5b4..49c768f 100644 --- a/lib/file_hash.nom +++ b/lib/file_hash.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file defines some actions for hashing files and looking up files by hash. diff --git a/lib/object.nom b/lib/object.nom index cb5cd3c..ae52d99 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file contains the implementation of an Object-Oriented programming system. diff --git a/lib/os.nom b/lib/os.nom index 57dac26..e29b5d1 100644 --- a/lib/os.nom +++ b/lib/os.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file defines some actions that interact with the operating system and filesystem. diff --git a/lib/training_wheels.nom b/lib/training_wheels.nom index 4c0b166..2845768 100644 --- a/lib/training_wheels.nom +++ b/lib/training_wheels.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file contains a set of definitions that bring some familiar language features from other languages into nomsu (e.g. "==" and "continue") @@ -11,7 +11,7 @@ parse [%a === %b] as ((%a 's id) is (%b 's id)) parse [%a !== %b] as ((%a 's id) is not (%b 's id)) parse [%a mod %b] as (%a wrapped around %b) parse [function %names %body, def %names %body] as (action %names %body) -parse [switch %branch_value %body] as (when %branch_value = ? %body) +parse [switch %branch_value %body] as (if %branch_value is: %body) parse [None, Null] as (nil) parse [True, true] as (yes) parse [False, false] as (no) diff --git a/lib/version.nom b/lib/version.nom index 952d940..3380301 100644 --- a/lib/version.nom +++ b/lib/version.nom @@ -1,3 +1,3 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # This file sets the current library version. lua> "NOMSU_LIB_VERSION = 3" \ No newline at end of file diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index da4a155..b4702ed 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -227,18 +227,19 @@ do }) NomsuCompiler.LOADED = { } NomsuCompiler.AST = AST - NomsuCompiler.compile_error = function(self, tok, err_format_string, ...) - local file = files.read(tok.source.filename) + NomsuCompiler.compile_error = function(self, source, err_format_string, ...) + err_format_string = err_format_string:gsub("%%[^s]", "%%%1") + local file = files.read(source.filename) local line_starts = files.get_line_starts(file) - local line_no = files.get_line_number(file, tok.source.start) + local line_no = files.get_line_number(file, source.start) local line_start = line_starts[line_no] - local src = colored.dim(file:sub(line_start, tok.source.start - 1)) - src = src .. colored.underscore(colored.bright(colored.red(file:sub(tok.source.start, tok.source.stop - 1)))) - local end_of_line = (line_starts[files.get_line_number(file, tok.source.stop) + 1] or 0) - 1 - src = src .. colored.dim(file:sub(tok.source.stop, end_of_line - 1)) + local src = colored.dim(file:sub(line_start, source.start - 1)) + src = src .. colored.underscore(colored.bright(colored.red(file:sub(source.start, source.stop - 1)))) + local end_of_line = (line_starts[files.get_line_number(file, source.stop) + 1] or 0) - 1 + src = src .. colored.dim(file:sub(source.stop, end_of_line - 1)) src = ' ' .. src:gsub('\n', '\n ') local err_msg = err_format_string:format(src, ...) - return error(tostring(tok.source.filename) .. ":" .. tostring(line_no) .. ": " .. err_msg, 0) + return error(tostring(source.filename) .. ":" .. tostring(line_no) .. ": " .. err_msg, 0) end local math_expression = re.compile([[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]]) local add_lua_bits @@ -256,7 +257,7 @@ do else local bit_lua = self:compile(bit) if not (bit_lua.is_value) then - self:compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.") + self:compile_error(bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.") end lua:append(bit_lua) end @@ -289,7 +290,7 @@ do else local bit_lua = self:compile(bit) if not (bit_lua.is_value) then - self:compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.") + self:compile_error(bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.") end add_bit_lua(lua, bit_lua) end @@ -308,7 +309,7 @@ do else local tok_lua = self:compile(tok) if not (tok_lua.is_value) then - self:compile_error(tok, "Non-expression value inside math expression:\n%s") + self:compile_error(tok.source, "Non-expression value inside math expression:\n%s") end if tok.type == "Action" then tok_lua:parenthesize() @@ -456,7 +457,7 @@ do source = nil end local lua_string = tostring(lua) - local run_lua_fn, err = load(lua_string, tostring(source or lua.source), "t", self) + local run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self) if not run_lua_fn then local line_numbered_lua = concat((function() local _accum_0 = { } @@ -540,7 +541,7 @@ do end local ret = compile_action(self, tree, unpack(args)) if not ret then - self:compile_error(tree, "Compile-time action:\n%s\nfailed to produce any Lua") + self:compile_error(tree.source, "Compile-time action:\n%s\nfailed to produce any Lua") end return ret end @@ -556,7 +557,7 @@ do end local arg_lua = self:compile(tok) if not (arg_lua.is_value) then - self:compile_error(tok, "Cannot use:\n%s\nas an argument to %s, since it's not an expression, it produces: %s", stub, repr(arg_lua)) + self:compile_error(tok.source, "Cannot use:\n%s\nas an argument to %s, since it's not an expression, it produces: %s", stub, repr(arg_lua)) end insert(args, arg_lua) _continue_0 = true @@ -624,7 +625,7 @@ do if not (bit_lua.is_value) then local src = ' ' .. gsub(tostring(recurse(bit)), '\n', '\n ') local line = tostring(bit.source.filename) .. ":" .. tostring(files.get_line_number(files.read(bit.source.filename), bit.source.start)) - self:compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.") + self:compile_error(bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.") end if #lua.bits > 0 then lua:append("..") @@ -655,7 +656,7 @@ do for i, item in ipairs(tree) do local item_lua = self:compile(item) if not (item_lua.is_value) then - self:compile_error(item, "Cannot use:\n%s\nas a list item, since it's not an expression.") + self:compile_error(item.source, "Cannot use:\n%s\nas a list item, since it's not an expression.") end items[i] = item_lua end @@ -680,11 +681,11 @@ do local key, value = tree[1], tree[2] local key_lua = self:compile(key) if not (key_lua.is_value) then - self:compile_error(tree[1], "Cannot use:\n%s\nas a dict key, since it's not an expression.") + self:compile_error(tree[1].source, "Cannot use:\n%s\nas a dict key, since it's not an expression.") end local value_lua = value and self:compile(value) or LuaCode.Value(key.source, "true") if not (value_lua.is_value) then - self:compile_error(tree[2], "Cannot use:\n%s\nas a dict value, since it's not an expression.") + self:compile_error(tree[2].source, "Cannot use:\n%s\nas a dict value, since it's not an expression.") end local key_str = match(tostring(key_lua), [=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=]) if key_str then @@ -697,7 +698,7 @@ do elseif "IndexChain" == _exp_0 then local lua = self:compile(tree[1]) if not (lua.is_value) then - self:compile_error(tree[1], "Cannot index:\n%s\nsince it's not an expression.") + self:compile_error(tree[1].source, "Cannot index:\n%s\nsince it's not an expression.") end local first_char = sub(tostring(lua), 1, 1) if first_char == "{" or first_char == '"' or first_char == "[" then @@ -707,7 +708,7 @@ do local key = tree[i] local key_lua = self:compile(key) if not (key_lua.is_value) then - self:compile_error(key, "Cannot use:\n%s\nas an index, since it's not an expression.") + self:compile_error(key.source, "Cannot use:\n%s\nas an index, since it's not an expression.") end local key_lua_str = tostring(key_lua) do @@ -833,7 +834,7 @@ do return nomsu else local pos = tree.source.start - local nomsu = NomsuCode(tree.source, pop_comments(pos, '\n')) + local nomsu = NomsuCode(tree.source, pop_comments(pos)) local next_space = "" for i, bit in ipairs(tree) do if match(next_space, '\n') then diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index dd08994..5b9b3f6 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -124,18 +124,19 @@ with NomsuCompiler .LOADED = {} .AST = AST - .compile_error = (tok, err_format_string, ...)=> - file = files.read(tok.source.filename) + .compile_error = (source, err_format_string, ...)=> + err_format_string = err_format_string\gsub("%%[^s]", "%%%1") + file = files.read(source.filename) line_starts = files.get_line_starts(file) - line_no = files.get_line_number(file, tok.source.start) + line_no = files.get_line_number(file, source.start) line_start = line_starts[line_no] - src = colored.dim(file\sub(line_start, tok.source.start-1)) - src ..= colored.underscore colored.bright colored.red(file\sub(tok.source.start, tok.source.stop-1)) - end_of_line = (line_starts[files.get_line_number(file, tok.source.stop) + 1] or 0) - 1 - src ..= colored.dim(file\sub(tok.source.stop, end_of_line-1)) + src = colored.dim(file\sub(line_start, source.start-1)) + src ..= colored.underscore colored.bright colored.red(file\sub(source.start, source.stop-1)) + end_of_line = (line_starts[files.get_line_number(file, source.stop) + 1] or 0) - 1 + src ..= colored.dim(file\sub(source.stop, end_of_line-1)) src = ' '..src\gsub('\n', '\n ') err_msg = err_format_string\format(src, ...) - error("#{tok.source.filename}:#{line_no}: "..err_msg, 0) + error("#{source.filename}:#{line_no}: "..err_msg, 0) -- This is a bit of a hack, but this code handles arbitrarily complex -- math expressions like 2*x + 3^2 without having to define a single @@ -154,7 +155,7 @@ with NomsuCompiler else bit_lua = @compile(bit) unless bit_lua.is_value - @compile_error bit, + @compile_error bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression." lua\append bit_lua return lua @@ -178,7 +179,7 @@ with NomsuCompiler else bit_lua = @compile(bit) unless bit_lua.is_value - @compile_error bit, + @compile_error bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression." add_bit_lua(lua, bit_lua) lua\append ")" @@ -194,7 +195,7 @@ with NomsuCompiler else tok_lua = @compile(tok) unless tok_lua.is_value - @compile_error tok, "Non-expression value inside math expression:\n%s" + @compile_error tok.source, "Non-expression value inside math expression:\n%s" if tok.type == "Action" tok_lua\parenthesize! lua\append tok_lua @@ -293,7 +294,7 @@ with NomsuCompiler .run_lua = (lua, source=nil)=> lua_string = tostring(lua) - run_lua_fn, err = load(lua_string, tostring(source or lua.source), "t", self) + run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self) if not run_lua_fn line_numbered_lua = concat( [format("%3d|%s",i,line) for i, line in ipairs files.get_lines(lua_string)], @@ -340,7 +341,7 @@ with NomsuCompiler -- TODO: use tail call? ret = compile_action(@, tree, unpack(args)) if not ret - @compile_error tree, + @compile_error tree.source, "Compile-time action:\n%s\nfailed to produce any Lua" return ret @@ -350,7 +351,7 @@ with NomsuCompiler if type(tok) == "string" then continue arg_lua = @compile(tok) unless arg_lua.is_value - @compile_error tok, + @compile_error tok.source, "Cannot use:\n%s\nas an argument to %s, since it's not an expression, it produces: %s", stub, repr arg_lua insert args, arg_lua @@ -387,7 +388,7 @@ with NomsuCompiler unless bit_lua.is_value src = ' '..gsub(tostring(recurse(bit)), '\n','\n ') line = "#{bit.source.filename}:#{files.get_line_number(files.read(bit.source.filename), bit.source.start)}" - @compile_error bit, + @compile_error bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression." if #lua.bits > 0 then lua\append ".." if bit.type != "Text" @@ -408,7 +409,7 @@ with NomsuCompiler for i, item in ipairs tree item_lua = @compile(item) unless item_lua.is_value - @compile_error item, + @compile_error item.source, "Cannot use:\n%s\nas a list item, since it's not an expression." items[i] = item_lua lua\concat_append(items, ", ", ",\n ") @@ -425,11 +426,11 @@ with NomsuCompiler key, value = tree[1], tree[2] key_lua = @compile(key) unless key_lua.is_value - @compile_error tree[1], + @compile_error tree[1].source, "Cannot use:\n%s\nas a dict key, since it's not an expression." value_lua = value and @compile(value) or LuaCode.Value(key.source, "true") unless value_lua.is_value - @compile_error tree[2], + @compile_error tree[2].source, "Cannot use:\n%s\nas a dict value, since it's not an expression." -- TODO: support arbitrary words here, like operators and unicode key_str = match(tostring(key_lua), [=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=]) @@ -446,7 +447,7 @@ with NomsuCompiler when "IndexChain" lua = @compile(tree[1]) unless lua.is_value - @compile_error tree[1], + @compile_error tree[1].source, "Cannot index:\n%s\nsince it's not an expression." first_char = sub(tostring(lua),1,1) if first_char == "{" or first_char == '"' or first_char == "[" @@ -456,7 +457,7 @@ with NomsuCompiler key = tree[i] key_lua = @compile(key) unless key_lua.is_value - @compile_error key, + @compile_error key.source, "Cannot use:\n%s\nas an index, since it's not an expression." key_lua_str = tostring(key_lua) if lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$") @@ -539,7 +540,7 @@ with NomsuCompiler return nomsu else pos = tree.source.start - nomsu = NomsuCode(tree.source, pop_comments(pos, '\n')) + nomsu = NomsuCode(tree.source, pop_comments(pos)) next_space = "" for i,bit in ipairs tree if match(next_space, '\n') diff --git a/tests/collections.nom b/tests/collections.nom index cf60ebe..f8b813f 100644 --- a/tests/collections.nom +++ b/tests/collections.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 #.. Tests for the stuff defined in core/control_flow.nom use "core" diff --git a/tests/colors.nom b/tests/colors.nom index d4d5ac5..da1b2e3 100644 --- a/tests/colors.nom +++ b/tests/colors.nom @@ -1,3 +1,3 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 use "lib/consolecolor.nom" say (bright (green "Color test passed.")) \ No newline at end of file diff --git a/tests/control_flow.nom b/tests/control_flow.nom index 1d223a4..6312d77 100644 --- a/tests/control_flow.nom +++ b/tests/control_flow.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # Tests for the stuff defined in core/control_flow.nom @@ -107,37 +107,35 @@ for %key = %value in {x: 1, y: 2}: do next %value barf "skipping value failed" -action [barfer] (barf "this should never be reached") -when: - * (no) (barf "'when' fail") - * (no) - * (3 > 4) (barf "'when' fail 2") - * (yes) - * (barfer) (do nothing) - * (99 > 1) (barf "Fell through incorrectly") +action [barfer]: barf "this should never be reached" +if: + (no): barf "'when' fail" + (no) (3 > 4): barf "'when' fail 2" + (yes) (barfer): do nothing + (99 > 1): barf "Fell through incorrectly" %else_worked = (no) -when: - * (no) (barf) - *else (%else_worked = (yes)) +if: + (no): barf + else: %else_worked = (yes) + + assume %else_worked or barf "when..else failed" -action [test when scope] (when (* (yes) (%leaked = (yes)))) +action [test when scope]: + if (yes): %leaked = (yes) test when scope assume (not %leaked) or barf "'when' is leaking locals" %when_worked = (no) -when 4 = ?: - * 1 - * 2 (barf "'when = ?' fail") - * 3 - * 4 - * (barfer) (%when_worked = (yes)) +if 4 is: + 1 2: barf "'when = ?' fail" + 3 4 (barfer): %when_worked = (yes) assume %when_worked %when_worked = (no) -when 5 = ?: - * 6 (barf) - *else (%when_worked = (yes)) +if 5 is: + 6: barf + else: %when_worked = (yes) assume %when_worked %x = 1 @@ -149,8 +147,7 @@ assume (..) %n = 0 for % in [1, 2, 3]: %n += % return %n - ..== 6 - + .. == 6 %t = [1, [2, [[3], 4], 5, [[[6]]]]] %flat = [] for % in recursive %t: diff --git a/tests/coroutines.nom b/tests/coroutines.nom index 54b233e..a67e1c8 100644 --- a/tests/coroutines.nom +++ b/tests/coroutines.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # Tests for the stuff defined in core/control_flow.nom diff --git a/tests/errors.nom b/tests/errors.nom index 7f91c88..af918a6 100644 --- a/tests/errors.nom +++ b/tests/errors.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # Tests for the stuff defined in core/errors.nom diff --git a/tests/inner/inner.nom b/tests/inner/inner.nom index a4341f0..903e0c0 100644 --- a/tests/inner/inner.nom +++ b/tests/inner/inner.nom @@ -1,3 +1,3 @@ -#!/usr/bin/env nomsu -V1 +#!/usr/bin/env nomsu -V2.4.4.3 use "core" -say "Inner directory 'use' test passed." +say "Inner directory 'use' test passed." \ No newline at end of file diff --git a/tests/math.nom b/tests/math.nom index 7ddefba..f740315 100644 --- a/tests/math.nom +++ b/tests/math.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 #.. Tests for the stuff defined in core/control_flow.nom use "core" diff --git a/tests/metaprogramming.nom b/tests/metaprogramming.nom index d74542c..b8dfde0 100644 --- a/tests/metaprogramming.nom +++ b/tests/metaprogramming.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # Tests for the stuff defined in core/metaprogramming.nom @@ -68,4 +68,4 @@ lua> %code assume (=lua "global_x") or barf "Running lua from a variable failed." %code = (Lua value "global_x") assume (=lua %code) or barf "Running lua from a variable failed." -say "Metaprogramming test passed." +say "Metaprogramming test passed." \ No newline at end of file diff --git a/tests/object.nom b/tests/object.nom index 30cf748..186957d 100644 --- a/tests/object.nom +++ b/tests/object.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # Tests for the object model defined in lib/object.nom diff --git a/tests/operators.nom b/tests/operators.nom index 0ab44c1..a8f7bfd 100644 --- a/tests/operators.nom +++ b/tests/operators.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 #.. Tests for the stuff defined in core/operators.nom use "core" @@ -69,4 +69,4 @@ assume (%x == 2) or barf "+<- failed" assume (%x == 4) or barf "*<- failed" wrap %x around 3 assume (%x == 1) or barf "wrap around failed" -say "Operator test passed." +say "Operator test passed." \ No newline at end of file diff --git a/tests/os.nom b/tests/os.nom index cbda5b3..c96306b 100644 --- a/tests/os.nom +++ b/tests/os.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 # Tests for the stuff defined in lib/os.nom diff --git a/tests/scopes.nom b/tests/scopes.nom index a882dcb..4d20dd7 100644 --- a/tests/scopes.nom +++ b/tests/scopes.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 use "core" %x = "outer" with local %x: diff --git a/tests/text.nom b/tests/text.nom index 316b343..a002445 100644 --- a/tests/text.nom +++ b/tests/text.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env nomsu -V2.3.4.3 +#!/usr/bin/env nomsu -V2.4.4.3 #.. Tests for the stuff defined in core/text.nom use "core" @@ -40,10 +40,9 @@ assume (..) ..== "one\ntwo" assume ("nogap" == "nogap") + #comment # block comment - - say "Text test passed." \ No newline at end of file diff --git a/tools/upgrade.nom b/tools/upgrade.nom index 14f7ee0..8f478ac 100644 --- a/tools/upgrade.nom +++ b/tools/upgrade.nom @@ -1,4 +1,4 @@ -#!/usr/bin/env Nomsu -V2.3.4.3 +#!/usr/bin/env Nomsu -V2.4.4.3 use "core" use "compatibility" use "lib/os.nom" @@ -8,14 +8,25 @@ use "lib/os.nom" if (%args.1 is "-i"): %inplace = (yes) remove index 1 from %args +if (%args.1 is "-t"): + use "lib/consolecolor.nom" + %test = (yes) + remove index 1 from %args for %path in %args: if (%path is "-i"): %inplace = (yes) for file %filename in %path: %tree = (parse (read file %filename) from %filename) - %tree = (%tree upgraded from %tree.version to (Nomsu version)) - %text = "#!/usr/bin/env nomsu -V\(Nomsu version)\n\(%tree as nomsu)" - if %inplace: - write %text to file %filename - ..else: - say %text + %uptree = (%tree upgraded from %tree.version to (Nomsu version)) + %text = "#!/usr/bin/env nomsu -V\(Nomsu version)\n\(%uptree as nomsu)" + if: + %inplace: + say "Upgraded \%filename" + write %text to file %filename + %test: + if (%uptree == %tree): + say (dim "\%filename will not be changed") + ..else: + say (bright "\%filename will be changed") + else: + say %text