aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--error_handling.lua31
-rw-r--r--error_handling.moon34
-rw-r--r--lib/consolecolor/init.nom15
-rw-r--r--lib/core/errors.nom1
-rw-r--r--lib/progressbar/init.nom25
-rwxr-xr-xlib/tools/repl.nom3
-rwxr-xr-xlib/tools/tutorial.nom203
-rw-r--r--nomsu.lua14
-rwxr-xr-xnomsu.moon17
-rw-r--r--nomsu_compiler.lua12
-rw-r--r--nomsu_compiler.moon13
-rw-r--r--nomsu_environment.lua34
-rw-r--r--nomsu_environment.moon35
-rw-r--r--pretty_errors.lua32
-rw-r--r--pretty_errors.moon26
16 files changed, 316 insertions, 183 deletions
diff --git a/Makefile b/Makefile
index ad6a9a5..0da53ea 100644
--- a/Makefile
+++ b/Makefile
@@ -14,11 +14,11 @@ UNINSTALL_VERSION=
MOON_FILES= code_obj.moon error_handling.moon files.moon nomsu.moon nomsu_compiler.moon \
syntax_tree.moon containers.moon bitops.moon parser.moon pretty_errors.moon \
text.moon nomsu_decompiler.moon nomsu_environment.moon bootstrap.moon \
- builtin_metatables.moon
+ builtin_metatables.moon colors.moon
LUA_FILES= code_obj.lua error_handling.lua files.lua nomsu.lua nomsu_compiler.lua \
syntax_tree.lua containers.lua bitops.lua parser.lua pretty_errors.lua \
text.lua nomsu_decompiler.lua nomsu_environment.lua bootstrap.lua \
- builtin_metatables.lua
+ builtin_metatables.lua colors.lua
CORE_NOM_FILES=$(shell cat lib/core/init.nom | sed -n 's;export "\(.*\)";lib/\1.nom;p') lib/core/init.nom
CORE_LUA_FILES= $(patsubst %.nom,%.lua, $(CORE_NOM_FILES))
COMPAT_NOM_FILES=$(wildcard lib/compatibility/*.nom)
diff --git a/error_handling.lua b/error_handling.lua
index fd6572e..b7d5d13 100644
--- a/error_handling.lua
+++ b/error_handling.lua
@@ -1,14 +1,7 @@
local debug_getinfo = debug.getinfo
local Files = require("files")
+local C = require("colors")
local pretty_error = require("pretty_errors")
-local RED = "\027[31m"
-local BRIGHT_RED = "\027[31;1m"
-local RESET = "\027[0m"
-local YELLOW = "\027[33m"
-local CYAN = "\027[36m"
-local GREEN = "\027[32m"
-local BLUE = "\027[34m"
-local DIM = "\027[37;2m"
local ok, to_lua = pcall(function()
return require('moonscript.base').to_lua
end)
@@ -66,10 +59,10 @@ debug.getinfo = function(thread, f, what)
end
local enhance_error
enhance_error = function(error_message, start_fn, stop_fn)
- if not (error_message and error_message:match("\x1b")) then
+ if not (error_message and error_message:match("%d|")) then
error_message = error_message or ""
do
- local fn = error_message:match("attempt to call a nil value %(global '(.*)'%)")
+ local fn = (error_message:match("attempt to call a nil value %(global '(.*)'%)") or error_message:match("attempt to call global '(.*)' %(a nil value%)"))
if fn then
error_message = "The action '" .. tostring(fn:from_lua_id()) .. "' is not defined."
end
@@ -130,7 +123,7 @@ enhance_error = function(error_message, start_fn, stop_fn)
end
end
local ret = {
- tostring(RED) .. "ERROR: " .. tostring(BRIGHT_RED) .. tostring(error_message or "") .. tostring(RESET),
+ C('bold red', error_message or "Error"),
"stack traceback:"
}
local level = 2
@@ -181,10 +174,10 @@ enhance_error = function(error_message, start_fn, stop_fn)
do
local err_line = lines[calling_fn.currentline]
if err_line then
- local offending_statement = tostring(BRIGHT_RED) .. tostring(err_line:match("^[ ]*(.*)")) .. tostring(RESET)
- line = tostring(YELLOW) .. tostring(filename) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name) .. "\n " .. tostring(offending_statement) .. tostring(RESET)
+ local offending_statement = C('bright red', err_line:match("^[ ]*(.*)"))
+ line = C('yellow', tostring(filename) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name) .. "\n " .. tostring(offending_statement))
else
- line = tostring(YELLOW) .. tostring(filename) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name) .. tostring(RESET)
+ line = C('yellow', tostring(filename) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name))
end
end
else
@@ -236,20 +229,20 @@ enhance_error = function(error_message, start_fn, stop_fn)
if file and (calling_fn.short_src:match("%.moon$") or file:match("^#![^\n]*moon\n")) and type(MOON_SOURCE_MAP[file]) == 'table' then
local char = MOON_SOURCE_MAP[file][calling_fn.currentline]
line_num = file:line_number_at(char)
- line = tostring(CYAN) .. tostring(calling_fn.short_src) .. ":" .. tostring(line_num) .. " in " .. tostring(name or '?') .. tostring(RESET)
+ line = C('cyan', tostring(calling_fn.short_src) .. ":" .. tostring(line_num) .. " in " .. tostring(name or '?'))
else
line_num = calling_fn.currentline
if calling_fn.short_src == '[C]' then
- line = tostring(GREEN) .. tostring(calling_fn.short_src) .. " in " .. tostring(name or '?') .. tostring(RESET)
+ line = C('green', tostring(calling_fn.short_src) .. " in " .. tostring(name or '?'))
else
- line = tostring(BLUE) .. tostring(calling_fn.short_src) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name or '?') .. tostring(RESET)
+ line = C('blue', tostring(calling_fn.short_src) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name or '?'))
end
end
if file then
do
local err_line = lines[line_num]
if err_line then
- local offending_statement = tostring(BRIGHT_RED) .. tostring(err_line:match("^[ ]*(.*)$")) .. tostring(RESET)
+ local offending_statement = C('bright red', tostring(err_line:match("^[ ]*(.*)$")))
line = line .. ("\n " .. offending_statement)
end
end
@@ -258,7 +251,7 @@ enhance_error = function(error_message, start_fn, stop_fn)
end
table.insert(ret, line)
if calling_fn.istailcall then
- table.insert(ret, " " .. tostring(DIM) .. "(...tail calls...)" .. tostring(RESET))
+ table.insert(ret, C('dim', " (...tail calls...)"))
end
_continue_0 = true
until true
diff --git a/error_handling.moon b/error_handling.moon
index 18ae4ef..ebd8309 100644
--- a/error_handling.moon
+++ b/error_handling.moon
@@ -1,18 +1,10 @@
-- This file contains the logic for making nicer error messages
debug_getinfo = debug.getinfo
Files = require "files"
+C = require "colors"
pretty_error = require("pretty_errors")
export SOURCE_MAP
-RED = "\027[31m"
-BRIGHT_RED = "\027[31;1m"
-RESET = "\027[0m"
-YELLOW = "\027[33m"
-CYAN = "\027[36m"
-GREEN = "\027[32m"
-BLUE = "\027[34m"
-DIM = "\027[37;2m"
-
ok, to_lua = pcall -> require('moonscript.base').to_lua
if not ok then to_lua = -> nil
MOON_SOURCE_MAP = setmetatable {},
@@ -47,9 +39,11 @@ debug.getinfo = (thread,f,what)->
return info
enhance_error = (error_message, start_fn, stop_fn)->
- unless error_message and error_message\match("\x1b")
+ -- Hacky: detect the line numbering
+ unless error_message and error_message\match("%d|")
error_message or= ""
- if fn = error_message\match("attempt to call a nil value %(global '(.*)'%)")
+ if fn = (error_message\match("attempt to call a nil value %(global '(.*)'%)") or
+ error_message\match("attempt to call global '(.*)' %(a nil value%)"))
error_message = "The action '#{fn\from_lua_id!}' is not defined."
level = 2
while true
@@ -91,7 +85,7 @@ enhance_error = (error_message, start_fn, stop_fn)->
ret = {
- "#{RED}ERROR: #{BRIGHT_RED}#{error_message or ""}#{RESET}"
+ C('bold red', error_message or "Error")
"stack traceback:"
}
@@ -125,10 +119,10 @@ enhance_error = (error_message, start_fn, stop_fn)->
file = Files.read(filename)
lines = file and file\lines! or {}
if err_line = lines[calling_fn.currentline]
- offending_statement = "#{BRIGHT_RED}#{err_line\match("^[ ]*(.*)")}#{RESET}"
- line = "#{YELLOW}#{filename}:#{calling_fn.currentline} in #{name}\n #{offending_statement}#{RESET}"
+ offending_statement = C('bright red', err_line\match("^[ ]*(.*)"))
+ line = C('yellow', "#{filename}:#{calling_fn.currentline} in #{name}\n #{offending_statement}")
else
- line = "#{YELLOW}#{filename}:#{calling_fn.currentline} in #{name}#{RESET}"
+ line = C('yellow', "#{filename}:#{calling_fn.currentline} in #{name}")
else
local line_num
if name == nil
@@ -161,21 +155,21 @@ enhance_error = (error_message, start_fn, stop_fn)->
if file and (calling_fn.short_src\match("%.moon$") or file\match("^#![^\n]*moon\n")) and type(MOON_SOURCE_MAP[file]) == 'table'
char = MOON_SOURCE_MAP[file][calling_fn.currentline]
line_num = file\line_number_at(char)
- line = "#{CYAN}#{calling_fn.short_src}:#{line_num} in #{name or '?'}#{RESET}"
+ line = C('cyan', "#{calling_fn.short_src}:#{line_num} in #{name or '?'}")
else
line_num = calling_fn.currentline
if calling_fn.short_src == '[C]'
- line = "#{GREEN}#{calling_fn.short_src} in #{name or '?'}#{RESET}"
+ line = C('green', "#{calling_fn.short_src} in #{name or '?'}")
else
- line = "#{BLUE}#{calling_fn.short_src}:#{calling_fn.currentline} in #{name or '?'}#{RESET}"
+ line = C('blue', "#{calling_fn.short_src}:#{calling_fn.currentline} in #{name or '?'}")
if file
if err_line = lines[line_num]
- offending_statement = "#{BRIGHT_RED}#{err_line\match("^[ ]*(.*)$")}#{RESET}"
+ offending_statement = C('bright red', "#{err_line\match("^[ ]*(.*)$")}")
line ..= "\n "..offending_statement
table.insert ret, line
if calling_fn.istailcall
- table.insert ret, " #{DIM}(...tail calls...)#{RESET}"
+ table.insert ret, C('dim', " (...tail calls...)")
return table.concat(ret, "\n")
diff --git a/lib/consolecolor/init.nom b/lib/consolecolor/init.nom
index 27823b8..606f4b6 100644
--- a/lib/consolecolor/init.nom
+++ b/lib/consolecolor/init.nom
@@ -17,9 +17,12 @@ $colors = {
}
for $name = $colornum in $colors:
- $colornum = "\$colornum"
- \($name \$text) compiles to:
- if $text:
- return (Lua "('\\027[\($colornum)m'..\($text as lua expr)..'\\027[0m')")
- ..else:
- return (Lua "'\\027[\($colornum)m'")
+ (nomsu environment).($name, as lua id) =
+ for $text:
+ if $(COLOR ENABLED):
+ if $text:
+ return "\x1B[\($colornum)m\$text\x1b[0m"
+ ..else:
+ return "\x1B[\($colornum)m"
+ ..else:
+ return ($text or "")
diff --git a/lib/core/errors.nom b/lib/core/errors.nom
index b1f1941..6be7e7f 100644
--- a/lib/core/errors.nom
+++ b/lib/core/errors.nom
@@ -75,6 +75,7 @@ use "core/control_flow"
(assume $a == $b) parses as (assume ($a == $b))
(assume $a != $b) parses as (assume ($a != $b))
+(test that $condition) parses as (assume $condition)
test:
try: fail
diff --git a/lib/progressbar/init.nom b/lib/progressbar/init.nom
index 98efe11..b3fb3a2 100644
--- a/lib/progressbar/init.nom
+++ b/lib/progressbar/init.nom
@@ -1,12 +1,25 @@
#!/usr/bin/env nomsu -V6.15.13.8
# A progress bar
-
+use "consolecolor"
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+test:
+ assume (0 / 1 progress bar)
+ assume (10 wide 0.5 progress bar)
+
external:
($x / $w progress bar) means:
$x = ($x clamped between 0 and $w)
- $bits = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"]
- $middle = ("" if ($x == $w) else $bits.(1 + (floor ((#$bits) * ($x mod 1)))))
- return ("
- \027[0m[\027[32;40m\($bits, last, rep (floor $x))\$middle\(" ", rep ($w - ((floor $x) + 1)))\027[0m]
- ")
+ if $(COLOR ENABLED):
+ $bits = [" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█"]
+ $middle = ("" if ($x == $w) else $bits.(1 + (floor ((#$bits) * ($x mod 1)))))
+ return ("
+ \(reset color)[\(green)\($bits, last, rep (floor $x))\$middle\(" ", rep ($w - ((floor $x) + 1)))\(reset color)]
+ ")
+ ..else:
+ # Probably not unicode support either:
+ return ("
+ [\("#", rep ($x, rounded down))\("-", rep ($w - ($x, rounded down)))]
+ ")
($w wide $ progress bar) means (($ * $w) / $w progress bar)
diff --git a/lib/tools/repl.nom b/lib/tools/repl.nom
index 3d2318c..029df4a 100755
--- a/lib/tools/repl.nom
+++ b/lib/tools/repl.nom
@@ -52,7 +52,8 @@ command line program with $args:
if (($line == "\n") or (not $line)):
if ((size of $buff) > 0):
# clear the line
- say "\027[1A\027[2K" inline
+ if $(COLOR ENABLED):
+ say "\027[1A\027[2K" inline
go to (run buffer)
$buff, add ($line, with "\t" -> " ")
say (dim (yellow ".. ")) inline
diff --git a/lib/tools/tutorial.nom b/lib/tools/tutorial.nom
index 7c7d39c..dd26ada 100755
--- a/lib/tools/tutorial.nom
+++ b/lib/tools/tutorial.nom
@@ -25,11 +25,11 @@ $lessons = [
lesson "Variables":
# In Nomsu, variables have a "$" prefix, and you can just assign to them
without declaring them first:
- $x = 10
- assume ($x == 10)
+ $x = 1
+ test that ($x == 1)
# Variables which have not yet been set have the value (nil)
- assume ($foobar == (nil))
+ test that ($foobar == (nil))
# Variables can be nameless:
$ = 99
@@ -40,16 +40,15 @@ $lessons = [
# Figure out what value $my_var should have:
$my_var = 100
$my_var = ($my_var + $x + $(my favorite number))
- assume ($my_var == (???))
+ test that ($my_var == (???))
lesson "Actions":
- # Fix this action so the tests pass, then save and quit.
- # If the tests don't pass, you can come back to this file later.
+ # Fix this action so the tests pass:
($x doubled) means ((???) * $x)
# Tests:
- assume ((2 doubled) == 4)
- assume ((-5 doubled) == -10)
+ test that ((2 doubled) == 4)
+ test that ((-5 doubled) == -10)
lesson "Blocks":
# When you need to do multiple things inside an action, use a block.
@@ -64,6 +63,32 @@ $lessons = [
$correct_answer = (4 * ($num * $num))
if (($num doubled then squared) != $correct_answer):
fail "Wrong answer for \($num)!"
+
+ lesson "Text":
+ # Nomsu text is enclosed in double quotation marks:
+ $text = "Hello"
+
+ # You can insert values into text using a backslash:
+ test that ("two plus three is \(2 + 3)" == (???))
+
+ # Variables don't require parentheses, but other expressions do:
+ $x = 99
+ test that ("$x is \$x" == (???))
+
+ # This can be used to convert values to text:
+ test that ("\$x" == (???))
+
+ # Longer strings use '("' followed by an indented region:
+ $long = ("
+ line one
+ line two with spaces at the front
+ ")
+
+ test that
+ $long == ("
+ \(<your code here>)
+ \(<your code here>)
+ ")
lesson "Conditionals":
# Make this action return "big" if its argument
@@ -75,11 +100,11 @@ $lessons = [
<your code here>
# Tests:
- for $small_number in [0, 1, -5, -999, 99]:
- assume ((the size of $small_number) == "small")
-
for $big_number in [9999, 100]:
- assume ((the size of $big_number) == "big")
+ test that ((the size of $big_number) == "big")
+
+ for $small_number in [0, 1, -5, -999, 99]:
+ test that ((the size of $small_number) == "small")
lesson "Loops":
# Fix this action so the tests pass:
@@ -93,14 +118,14 @@ $lessons = [
return $sum
# Tests:
- assume ((the sum of [1, 2, 3, 4, 5]) == 15)
- assume ((the sum of [100, 200]) == 300)
+ test that ((the sum of [1, 2, 3, 4, 5]) == 15)
+ test that ((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 == (???))
+ test that ($total == (???))
lesson "Variable Scopes":
# Nomsu's variables are local by default, and actions have their own scopes:
@@ -111,17 +136,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 == (???))
+ test that ($y == (???))
# $x is set inside this action, and actions have their own scopes.
$x = $y
# What number should $x be here?
- assume ($x == (???))
+ test that ($x == (???))
# After running the action, what value should $x have?
do something
- assume ($x == (???))
+ test that ($x == (???))
lesson "More Variable Scopes":
# Loops and conditionals do *not* have their own scopes:
@@ -131,13 +156,13 @@ $lessons = [
$z = 2
# After assigning in a conditional, what should $z be?
- assume ($z == (???))
+ test that ($z == (???))
for $ in 1 to 1:
# Set $z inside a loop:
$z = 3
# After assigning in a loop, what should $z be?
- assume ($z == (???))
+ test that ($z == (???))
lesson "Externals":
# The 'external' block lets you modify variables outside an action:
@@ -147,7 +172,7 @@ $lessons = [
do something
# After running the action that sets $x in an 'external' block, what should $x be?
- assume ($x == (???))
+ test that ($x == (???))
lesson "Locals":
# The 'with' block lets you create a local scope for the variables you list:
@@ -158,8 +183,8 @@ $lessons = [
$z = 2
# After setting $y and $z in the 'with [$y]' block, what should $y and $z be?
- assume ($y == (???))
- assume ($z == (???))
+ test that ($y == (???))
+ test that ($z == (???))
lesson "Failure and Recovery":
$what_happened = "nothing"
@@ -174,7 +199,7 @@ $lessons = [
$what_happened = "success"
# What do you think happened?
- assume ($what_happened == (???))
+ test that ($what_happened == (???))
# Note: a 'try' block will silence failures, so this has no effect:
try: fail
@@ -182,11 +207,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 == (???))
+ test that ($dictionary.dog == "A lovable doofus")
+ test that ($dictionary.cat == (???))
# If you try to access a key that's not in an object, the result is (nil):
- assume ($dictionary.mimsy == (???))
+ test that ($dictionary.mimsy == (???))
# $dictionary.dog is just a shorthand for $dictionary."dog".
You may need to use the longer form for strings with spaces:
@@ -197,22 +222,22 @@ $lessons = [
$dictionary.5 = "The number five"
$dictionary.five = 5
$dictionary.myself = $dictionary
- assume ($dictionary.myself == (???))
+ test that ($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 == (???))
+ test that ($list.1 == "first")
+ test that ($list.2 == (???))
+ test that ($list.3 == (???))
# Hint: 4 should be a missing key
- assume ($list.4 == (???))
- assume ($list.foobar == (???))
+ test that ($list.4 == (???))
+ test that ($list.foobar == (???))
# The "#" action gets the number of items inside something:
- assume ((#$list) == (???))
- assume ((#{.x = 10, .y = 20}) == (???))
+ test that ((#$list) == (???))
+ test that ((#{.x = 10, .y = 20}) == (???))
lesson "Methods":
# The "," is used for method calls, which means calling an action
@@ -220,17 +245,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])
+ test that ($list == [-4, -6, 5, 3])
$list, add 7
- assume ($list == [???])
+ test that ($list == [???])
# Text also has some methods like:
$name = "Harry Tuttle"
- assume (($name, character 7) == "T")
- assume (($name, with "Tuttle" -> "Buttle") == (???))
+ test that (($name, from 7 to 12) == "Tuttle")
+ test that (($name, with "Tuttle" -> "Buttle") == (???))
# Methods can be chained too:
- assume (($name, with "Tuttle" -> "Buttle", character 7) == (???))
+ test that (($name, with "Tuttle" -> "Buttle", from 7 to 12) == (???))
lesson "Object Oriented Programming":
# Object Oriented Programming deals with things that have
@@ -246,13 +271,30 @@ $lessons = [
($self, add $bit) means:
$bits, add $bit
- # Write a method called ($self, length) that returns the total
- length of all the bits in the buffer:
+ # Write a method called ($self, length) that returns the sum
+ of the lengths of each bit in the buffer:
<your code here>
$b = (a Buffer)
$b, add "xx"
$b, add "yyy"
- assume (($b, length) == 5)
+ test that (($b, length) == 5)
+
+ lesson "Files Part 1":
+ # Define an external action here:
+ external:
+ # These will be used in the next lesson
+ $foobar = 23
+ ($x tripled) means:
+ <your code here>
+ test that ((5 tripled) == 15)
+ test that ((2 tripled) == 6)
+
+ lesson "Files Part 2":
+ # 'use' is the action for importing from other files
+ # It takes the path to the file (without the .nom extension):
+ use (<prev lesson>)
+ test that ((10 tripled) == (???))
+ test that ($foobar == (???))
]
$(ask normally) = $(ask)
@@ -282,14 +324,12 @@ command line program with $args:
unless ($Files.exists $tutorial_dir):
when
ask ("
- The Nomsu tutorial files will be in \$tutorial_dir is that okay? [Y/n] \;
+ The Nomsu tutorial files will be in \$tutorial_dir is that okay? [Y/n/exit] \;
")
..is:
"n" "N" "no":
- say ("
- Okay. If you want to specify another file location, run `nomsu -t tutorial <your location>`
- ")
- exit
+ $tutorial_dir = (ask "Where do you want to put the tutorial? ")
+ "exit" "quit" "q" "e": exit
..else:
$tutorial_dir = $args.extras.1
@@ -300,7 +340,10 @@ command line program with $args:
for $lesson in $lessons at $i:
$filename = (filename of $i)
unless ($Files.exists $filename):
- write $lesson.lesson to file $filename
+ $lesson_text =
+ $lesson.lesson, with "%(<prev lesson>%)" ->
+ "\"\(filename of ($i - 1), with "%.nom$" -> "", with "^%./" -> "")\""
+ write $lesson_text to file $filename
# Display info about editing the tutorial files:
if $args.x:
@@ -328,14 +371,23 @@ command line program with $args:
> \;
")
if ($EDITOR == ""): $EDITOR = (nil)
+
+ (run lesson $i) means:
+ $filename = (filename of $i)
+ $file = (read file $filename)
+ $file = ($NomsuCode, from (Source $filename 1 (#$file)) $file)
+ $tree = ($file parsed)
+ $tree =
+ $tree with $ ->:
+ if ($ == \(<prev lesson>)):
+ return ("Text" tree with (filename of ($i - 1), with "%.nom$" -> ""))
+ run $tree
+
(get failures) means [
: for $lesson in $lessons at $i:
- $filename = (filename of $i)
- $file = (read file $filename)
- $file = ($NomsuCode, from (Source $filename 1 (#$file)) $file)
try:
- run $file
+ run lesson $i
..if it fails with $msg:
$msg = ($msg, with "\n *stack traceback:.*" -> "")
add {.lesson_number = $i, .failure = $msg}
@@ -360,17 +412,21 @@ command line program with $args:
for $lesson in $lessons at $i:
for $f in $failures:
if ($f.lesson_number == $i):
- say (bold (red " \$i. \($lesson.name) [incomplete]"))
+ say "\(red " - ")\(bold (red "\$i. \($lesson.name) [incomplete]"))"
do next $lesson
- say (bold (green " \$i. \($lesson.name) [passed]"))
+ say "\(green " + ")\(bold (green "\$i. \($lesson.name) [passed]"))"
- say ("
+ if $(COLOR ENABLED):
+ say ("
+
+ \(bold "Your progress:") \(
+ 20 wide (((#$lessons) - (#$failures)) / (#$lessons)) progress bar
+ )
+ ")
+ ..else:
+ say
+ say (((#$lessons) - (#$failures)) / (#$lessons) progress bar)
- \(bold "Your progress:") \(
- 20 wide (((#$lessons) - (#$failures)) / (#$lessons)) progress bar
- )
- ")
-
repeat until ($failures is empty):
show first failure from $failures
@@ -400,6 +456,8 @@ command line program with $args:
--- (retry file) ---
when (ask "Edit \$filename to get it to pass? [Y/n/exit] ") is:
"q" "quit" "exit" "n" "N" "no": exit
+ "c":
+ write "# cheater!\n" to file $filename
"y" "Y" "yes" "":
$f = (read file $filename)
[$line, $col] = ($failures.1.failure, match ":(%d+),(%d+)")
@@ -422,10 +480,8 @@ command line program with $args:
else:
say "Sorry, I don't understand that."
go to (retry file)
- $file = (read file $filename)
- $file = ($NomsuCode, from (Source $filename 1 (#$file)) $file)
try:
- run $file
+ run lesson $failures.1.lesson_number
..if it fails with $msg:
$failures.1.failure = $msg
say (bold (red "\n There's a bit more to fix:"))
@@ -443,13 +499,16 @@ command line program with $args:
say (bold (green "\nSuccess!\n"))
..else:
say (bold (red "\nUh oh, that broke something.\n"))
- $N = 100
- for $ in 0 to $N:
- $k = (($ / $N) smoothed by 2)
- $p = ($prev_progress to $progress mixed by $k)
- say "\r\(bold "Your progress:") \(20 wide $p progress bar)" inline
- $io.flush()
- sleep for (1 / $N) seconds
+ if $(COLOR ENABLED):
+ $N = 100
+ for $ in 0 to $N:
+ $k = (($ / $N) smoothed by 2)
+ $p = ($prev_progress to $progress mixed by $k)
+ say "\r\(bold "Your progress:") \(20 wide $p progress bar)" inline
+ $io.flush()
+ sleep for (1 / $N) seconds
+ ..else:
+ say (((#$lessons) - (#$failures)) / (#$lessons) progress bar)
say
# All done, no more failures:
@@ -459,7 +518,7 @@ command line program with $args:
You've passed the tutorial!
- \\(^ᴗ^)/
+ \\(^\("ᴗ" if $(COLOR ENABLED) else "_")^)/
")
diff --git a/nomsu.lua b/nomsu.lua
index dc5b97f..21e4af2 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -1,16 +1,17 @@
local clibtype = package.cpath:match("?%.(so)") or package.cpath:match("?%.(dll)")
+COLOR_ENABLED = true
if clibtype == "dll" then
+ local enable_colors = require('wincolors')
+ local ok, _ = pcall(enable_colors)
+ if not ok then
+ COLOR_ENABLED = false
+ end
os.execute("chcp 65001>nul")
end
if NOMSU_VERSION and NOMSU_PREFIX then
package.path = tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(NOMSU_VERSION) .. "/?.lua;" .. package.path
package.cpath = tostring(NOMSU_PREFIX) .. "/lib/nomsu/" .. tostring(NOMSU_VERSION) .. "/?." .. tostring(clibtype) .. ";" .. package.cpath
end
-local EXIT_SUCCESS, EXIT_FAILURE = 0, 1
-if _VERSION == "Lua 5.1" and not jit then
- print("Sorry, Nomsu does not run on Lua 5.1. Please use LuaJIT 2+ or Lua 5.2+")
- os.exit(EXIT_FAILURE)
-end
local usage = [=[Nomsu Compiler
Usage: (nomsu | lua nomsu.lua | moon nomsu.moon) [-V version] [--help | -h] [--version] [-O optimization level] [-v] [-c] [-s] [-d debugger] [--no-core] [(file | -t tool | -e "nomsu code..." | files... -- ) [nomsu args...]]
@@ -92,7 +93,7 @@ local arg_string = table.concat(arg, sep) .. sep
local args, err = parser:match(arg_string)
if not args or err or args.help then
if err then
- print("Didn't understand: \x1b[31;1m" .. tostring(err) .. "\x1b[0m")
+ print("Didn't understand: " .. tostring(err))
end
print(usage)
os.exit(EXIT_FAILURE)
@@ -142,6 +143,7 @@ nomsu_environment.COMMAND_LINE_ARGS = nomsu_args
nomsu_environment.OPTIMIZATION = optimization
nomsu_environment.NOMSU_PACKAGEPATH = NOMSU_PACKAGEPATH
nomsu_environment.NOMSU_PREFIX = NOMSU_PREFIX
+nomsu_environment.COLOR_ENABLED = COLOR_ENABLED
local run
run = function()
if not (args.no_core) then
diff --git a/nomsu.moon b/nomsu.moon
index 240d457..96053eb 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -2,7 +2,14 @@
-- This file contains the command-line Nomsu runner.
clibtype = package.cpath\match("?%.(so)") or package.cpath\match("?%.(dll)")
+export COLOR_ENABLED
+COLOR_ENABLED = true
if clibtype == "dll"
+ -- Enable colors:
+ enable_colors = require('wincolors')
+ ok,_ = pcall(enable_colors)
+ if not ok
+ COLOR_ENABLED = false
-- Special hack to enable utf8 for windows console applications:
os.execute("chcp 65001>nul")
@@ -10,13 +17,6 @@ if NOMSU_VERSION and NOMSU_PREFIX
package.path = "#{NOMSU_PREFIX}/share/nomsu/#{NOMSU_VERSION}/?.lua;"..package.path
package.cpath = "#{NOMSU_PREFIX}/lib/nomsu/#{NOMSU_VERSION}/?.#{clibtype};"..package.cpath
-EXIT_SUCCESS, EXIT_FAILURE = 0, 1
-
-if _VERSION == "Lua 5.1" and not jit
- -- Cannot run on Lua5.1 because it doesn't have gotos.
- print("Sorry, Nomsu does not run on Lua 5.1. Please use LuaJIT 2+ or Lua 5.2+")
- os.exit(EXIT_FAILURE)
-
usage = [=[
Nomsu Compiler
@@ -91,7 +91,7 @@ arg_string = table.concat(arg, sep)..sep
args, err = parser\match(arg_string)
if not args or err or args.help
if err
- print("Didn't understand: \x1b[31;1m#{err}\x1b[0m")
+ print("Didn't understand: #{err}")
print usage
os.exit(EXIT_FAILURE)
nomsu_args = Dict{}
@@ -121,6 +121,7 @@ nomsu_environment.COMMAND_LINE_ARGS = nomsu_args
nomsu_environment.OPTIMIZATION = optimization
nomsu_environment.NOMSU_PACKAGEPATH = NOMSU_PACKAGEPATH
nomsu_environment.NOMSU_PREFIX = NOMSU_PREFIX
+nomsu_environment.COLOR_ENABLED = COLOR_ENABLED
run = ->
unless args.no_core
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 0cedd50..c9a15db 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -9,6 +9,7 @@ do
local _obj_0 = require("code_obj")
LuaCode, Source = _obj_0.LuaCode, _obj_0.Source
end
+require("text")
local SyntaxTree = require("syntax_tree")
local Files = require("files")
local pretty_error = require("pretty_errors")
@@ -20,6 +21,17 @@ fail_at = function(source, msg)
source = source.source
elseif type(source) == 'string' then
source = Source:from_string(source)
+ else
+ assert(source.short_src and source.currentline)
+ file = Files.read(source.short_src)
+ assert(file, "Could not find " .. tostring(source.short_src))
+ local lines = file:lines()
+ local start = 1
+ for i = 1, source.currentline - 1 do
+ start = start + #lines[i]
+ end
+ local stop = start + #lines[source.currentline]
+ source = Source(source.short_src, start, stop)
end
if source and not file then
file = Files.read(source.filename)
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index 3993490..73cc5a8 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -4,6 +4,7 @@
unpack or= table.unpack
{:match, :sub, :gsub, :format, :byte, :find} = string
{:LuaCode, :Source} = require "code_obj"
+require "text"
SyntaxTree = require "syntax_tree"
Files = require "files"
@@ -15,6 +16,18 @@ fail_at = (source, msg)->
source = source.source
elseif type(source) == 'string'
source = Source\from_string(source)
+ else
+ -- debug.getinfo() output:
+ assert(source.short_src and source.currentline)
+ file = Files.read(source.short_src)
+ assert file, "Could not find #{source.short_src}"
+ lines = file\lines!
+ start = 1
+ for i=1,source.currentline-1
+ start += #lines[i]
+ stop = start + #lines[source.currentline]
+ source = Source(source.short_src, start, stop)
+
if source and not file
file = Files.read(source.filename)
diff --git a/nomsu_environment.lua b/nomsu_environment.lua
index e359257..5ea6a62 100644
--- a/nomsu_environment.lua
+++ b/nomsu_environment.lua
@@ -12,6 +12,7 @@ local Text = require('text')
local SyntaxTree = require("syntax_tree")
local Files = require("files")
local Errhand = require("error_handling")
+local C = require("colors")
local make_parser = require("parser")
local pretty_error = require("pretty_errors")
local make_tree
@@ -65,7 +66,6 @@ do
local _obj_0 = require('nomsu_compiler')
compile, fail_at = _obj_0.compile, _obj_0.fail_at
end
-local _currently_running_files = List({ })
local _module_imports = { }
local _importer_mt = {
__index = function(self, k)
@@ -225,7 +225,7 @@ nomsu_environment = Importer({
err_strings = _accum_0
end
if num_errs > #err_strings then
- table.insert(err_strings, "\027[31;1m +" .. tostring(num_errs - #err_strings) .. " additional errors...\027[0m\n")
+ table.insert(err_strings, C("bright red", " +" .. tostring(num_errs - #err_strings) .. " additional errors...\n"))
end
error(table.concat(err_strings, '\n\n'), 0)
end
@@ -249,11 +249,27 @@ nomsu_environment = Importer({
return ret
end
end
- if _currently_running_files:has(path) then
- local i = _currently_running_files:index_of(path)
- _currently_running_files:add(path)
- local circle = _currently_running_files:from_1_to(i, -1)
- error("Circular import detected:\n " .. circle:joined_with("\n..imports "))
+ local currently_running = { }
+ for i = 2, 999 do
+ local info = debug.getinfo(i, 'f')
+ if not (info.func) then
+ break
+ end
+ if info.func == self.Module then
+ local n, upper_path = debug.getlocal(i, 3)
+ table.insert(currently_running, upper_path)
+ assert(n == "path")
+ if upper_path == path then
+ local circle = table.concat(currently_running, "', which imports '")
+ local err_i = 2
+ info = debug.getinfo(err_i)
+ while info and (info.func == self.Module or info.func == self.use or info.func == self.export) do
+ err_i = err_i + 1
+ info = debug.getinfo(err_i)
+ end
+ fail_at((info or debug.getinfo(2)), "Circular import: File '" .. tostring(path) .. "' imports '" .. circle .. "'")
+ end
+ end
end
local mod = self:new_environment()
mod.MODULE_NAME = package_name
@@ -263,12 +279,10 @@ nomsu_environment = Importer({
else
code = NomsuCode:from(Source(path, 1, #code), code)
end
- _currently_running_files:add(path)
local ret = mod:run(code)
if ret ~= nil then
mod = ret
end
- _currently_running_files:pop()
package.nomsuloaded[package_name] = mod
package.nomsuloaded[path] = mod
return mod
@@ -360,7 +374,7 @@ nomsu_environment = Importer({
lines = _accum_0
end
local line_numbered_lua = table.concat(lines, "\n")
- error("Failed to compile generated code:\n\027[1;34m" .. tostring(line_numbered_lua) .. "\027[0m\n\n" .. tostring(err), 0)
+ error("Failed to compile generated code:\n" .. tostring(C("bright blue", line_numbered_lua)) .. "\n\n" .. tostring(err), 0)
end
local source_key = tostring(source)
if not (self.SOURCE_MAP[source_key] or self.OPTIMIZATION >= 2) then
diff --git a/nomsu_environment.moon b/nomsu_environment.moon
index 1deac6f..d572f8c 100644
--- a/nomsu_environment.moon
+++ b/nomsu_environment.moon
@@ -6,6 +6,7 @@ Text = require 'text'
SyntaxTree = require "syntax_tree"
Files = require "files"
Errhand = require "error_handling"
+C = require "colors"
make_parser = require("parser")
pretty_error = require("pretty_errors")
@@ -35,7 +36,6 @@ for version=1,999
{:tree_to_nomsu, :tree_to_inline_nomsu} = require "nomsu_decompiler"
{:compile, :fail_at} = require('nomsu_compiler')
-_currently_running_files = List{} -- Used to check for circular imports in run_file_1_in
_module_imports = {}
_importer_mt = {__index: (k)=> _module_imports[@][k]}
Importer = (t, imports)->
@@ -108,12 +108,13 @@ nomsu_environment = Importer{
start:e.source.start, stop:e.source.stop, filename:e.source.filename
} for i, e in ipairs(errs) when i <= 3]
if num_errs > #err_strings
- table.insert(err_strings, "\027[31;1m +#{num_errs-#err_strings} additional errors...\027[0m\n")
+ table.insert(err_strings, C("bright red", " +#{num_errs-#err_strings} additional errors...\n"))
error(table.concat(err_strings, '\n\n'), 0)
return tree
Module: (package_name)=>
+ -- This *must* be the first local
local path
if package_name\match("%.nom$") or package_name\match("%.lua")
path = package_name
@@ -125,11 +126,26 @@ nomsu_environment = Importer{
if ret = package.nomsuloaded[package_name] or package.nomsuloaded[path]
return ret
- if _currently_running_files\has(path)
- i = _currently_running_files\index_of(path)
- _currently_running_files\add path
- circle = _currently_running_files\from_1_to(i, -1)
- error("Circular import detected:\n "..circle\joined_with("\n..imports "))
+ -- Traverse up the callstack to look for import loops
+ -- This is more reliable than keeping a list of running files, since
+ -- that gets messed up when errors occur.
+ currently_running = {}
+ for i=2,999
+ info = debug.getinfo(i, 'f')
+ break unless info.func
+ if info.func == @Module
+ n, upper_path = debug.getlocal(i, 3) -- 3 means "path"
+ table.insert(currently_running, upper_path)
+ assert(n == "path")
+ if upper_path == path
+ --circle = "\n "..table.concat(currently_running, "\n..imports ")
+ circle = table.concat(currently_running, "', which imports '")
+ err_i = 2
+ info = debug.getinfo(err_i)
+ while info and (info.func == @Module or info.func == @use or info.func == @export)
+ err_i += 1
+ info = debug.getinfo(err_i)
+ fail_at (info or debug.getinfo(2)), "Circular import: File '#{path}' imports '"..circle.."'"
mod = @new_environment!
mod.MODULE_NAME = package_name
code = Files.read(path)
@@ -137,11 +153,9 @@ nomsu_environment = Importer{
code = LuaCode\from(Source(path, 1, #code), code)
else
code = NomsuCode\from(Source(path, 1, #code), code)
- _currently_running_files\add path
ret = mod\run(code)
if ret != nil
mod = ret
- _currently_running_files\pop!
package.nomsuloaded[package_name] = mod
package.nomsuloaded[path] = mod
return mod
@@ -165,7 +179,6 @@ nomsu_environment = Importer{
imports[k] = v
for k,v in pairs(mod)
if rawget(@, k) == nil
- --if k != "_G" and k != "_ENV" and k != "COMPILE_RULES" and k != "MODULE_NAME"
@[k] = v
cr_imports = assert _module_imports[@COMPILE_RULES]
if mod.COMPILE_RULES
@@ -210,7 +223,7 @@ nomsu_environment = Importer{
if not run_lua_fn
lines =[("%3d|%s")\format(i,line) for i, line in ipairs lua_string\lines!]
line_numbered_lua = table.concat(lines, "\n")
- error("Failed to compile generated code:\n\027[1;34m#{line_numbered_lua}\027[0m\n\n#{err}", 0)
+ error("Failed to compile generated code:\n#{C("bright blue", line_numbered_lua)}\n\n#{err}", 0)
source_key = tostring(source)
unless @SOURCE_MAP[source_key] or @OPTIMIZATION >= 2
map = {}
diff --git a/pretty_errors.lua b/pretty_errors.lua
index ecc6cd2..a675f12 100644
--- a/pretty_errors.lua
+++ b/pretty_errors.lua
@@ -1,5 +1,6 @@
require("containers")
local Text = require('text')
+local C = require('colors')
local box
box = function(text)
local max_line = 0
@@ -8,7 +9,7 @@ box = function(text)
end
local ret = ("\n" .. text):gsub("\n([^\n]*)", function(line)
local line_len = #(line:gsub("\027%[[0-9;]*m", ""))
- return "\n" .. tostring(line) .. tostring((" "):rep(max_line - line_len)) .. " \027[0m"
+ return "\n" .. tostring(line) .. tostring((" "):rep(max_line - line_len)) .. " " .. C('reset')
end)
return ret:sub(2, -1), max_line
end
@@ -20,13 +21,16 @@ format_error = function(err)
local nl_indicator = (err_linepos > #err_line) and " " or ""
local fmt_str = " %" .. tostring(#tostring(err_linenum + context)) .. "d|"
local pointer = (" "):rep(err_linepos + #fmt_str:format(0) - 1) .. ("^"):rep(err_size)
- local err_msg = "\027[31;1m" .. tostring(err.title or "Error") .. " at " .. tostring(err.filename or '???') .. ":" .. tostring(err_linenum) .. "," .. tostring(err_linepos) .. "\027[0m"
+ local err_msg = C('bold red', err.title or "Error") .. C('red', " at " .. tostring(err.filename or '???') .. ":" .. tostring(err_linenum) .. "," .. tostring(err_linepos))
+ if not (COLOR_ENABLED) then
+ err_msg = err_msg .. "\n"
+ end
local lines = err.source:lines()
for i = err_linenum - context, err_linenum - 1 do
do
local line = lines[i]
if line then
- err_msg = err_msg .. "\n\027[2m" .. tostring(fmt_str:format(i)) .. "\027[0m" .. tostring(line) .. "\027[0m"
+ err_msg = err_msg .. ("\n" .. C('dim', fmt_str:format(i)) .. line)
end
end
end
@@ -34,8 +38,8 @@ format_error = function(err)
local before = err_line:sub(1, err_linepos - 1)
local during = err_line:sub(err_linepos, err_linepos + err_size - 1)
local after = err_line:sub(err_linepos + err_size, -1)
- err_line = "\027[0m" .. tostring(before) .. "\027[41;30m" .. tostring(during) .. tostring(nl_indicator) .. "\027[0m" .. tostring(after)
- err_msg = err_msg .. "\n\027[2m" .. tostring(fmt_str:format(err_linenum)) .. tostring(err_line) .. "\027[0m"
+ err_line = before .. C('black on red', during .. nl_indicator) .. after
+ err_msg = err_msg .. ("\n" .. C('dim', fmt_str:format(err_linenum)) .. err_line)
end
local _, err_linenum_end, err_linepos_end = err.source:line_info_at(err.stop)
err_linenum_end = err_linenum_end or err_linenum
@@ -48,9 +52,9 @@ format_error = function(err)
if line then
if i == err_linenum_end then
local during, after = line:sub(1, err_linepos_end - 1), line:sub(err_linepos_end, -1)
- err_msg = err_msg .. "\n\027[2m" .. tostring(fmt_str:format(i)) .. "\027[0;41;30m" .. tostring(during) .. "\027[0m" .. tostring(after)
+ err_msg = err_msg .. ("\n" .. C('dim', fmt_str:format(i)) .. C('black on red', during) .. after)
else
- err_msg = err_msg .. "\n\027[2m" .. tostring(fmt_str:format(i)) .. "\027[0;41;30m" .. tostring(line) .. "\027[0m"
+ err_msg = err_msg .. ("\n" .. C('dim', fmt_str:format(i)) .. C('black on red', line))
end
end
end
@@ -61,19 +65,25 @@ format_error = function(err)
end
end
local box_width = 70
- local err_text = "\027[47;30;1m" .. tostring(" " .. err.error:wrapped_to(box_width, 16):gsub("\n", "\n\027[47;30;1m "))
+ local err_text = C('black on white', " " .. err.error:wrapped_to(box_width, 16):gsub("\n", "\n" .. C('black on white') .. " "))
if err.hint then
- err_text = err_text .. "\n\027[47;30;3m" .. tostring((" Suggestion: " .. tostring(err.hint)):wrapped_to(box_width, 16):gsub("\n", "\n\027[47;30;3m "))
+ err_text = err_text .. ("\n" .. C('italic black on white', (" Suggestion: " .. tostring(err.hint)):wrapped_to(box_width, 16):gsub("\n", "\n" .. C('italic black on white') .. " ")))
+ end
+ err_msg = err_msg .. ("\n " .. box(err_text):gsub("\n", "\n "))
+ if not (COLOR_ENABLED) then
+ err_msg = err_msg .. "\n"
end
- err_msg = err_msg .. ("\n\027[33;1m " .. box(err_text):gsub("\n", "\n "))
for i = err_linenum_end + 1, err_linenum_end + context do
do
local line = lines[i]
if line then
- err_msg = err_msg .. "\n\027[2m" .. tostring(fmt_str:format(i)) .. "\027[0m" .. tostring(line) .. "\027[0m"
+ err_msg = err_msg .. ("\n" .. C('dim', fmt_str:format(i)) .. line)
end
end
end
+ if not (COLOR_ENABLED) then
+ err_msg = err_msg .. "\n"
+ end
return err_msg
end
return format_error
diff --git a/pretty_errors.moon b/pretty_errors.moon
index bb8f63f..b769d32 100644
--- a/pretty_errors.moon
+++ b/pretty_errors.moon
@@ -2,6 +2,7 @@
-- line numbers, code excerpts, and so on.
require "containers"
Text = require 'text'
+C = require 'colors'
box = (text)->
max_line = 0
@@ -9,7 +10,7 @@ box = (text)->
max_line = math.max(max_line, #(line\gsub("\027%[[0-9;]*m","")))
ret = ("\n"..text)\gsub "\n([^\n]*)", (line)->
line_len = #(line\gsub("\027%[[0-9;]*m",""))
- return "\n#{line}#{(" ")\rep(max_line-line_len)} \027[0m"
+ return "\n#{line}#{(" ")\rep(max_line-line_len)} "..C('reset')
return ret\sub(2,-1), max_line
format_error = (err)->
@@ -26,17 +27,18 @@ format_error = (err)->
--else
-- (" ")\rep(err_linepos+#fmt_str\format(0)-1).."⬆"
- err_msg = "\027[31;1m#{err.title or "Error"} at #{err.filename or '???'}:#{err_linenum},#{err_linepos}\027[0m"
+ err_msg = C('bold red', err.title or "Error")..C('red', " at #{err.filename or '???'}:#{err_linenum},#{err_linepos}")
+ err_msg ..= "\n" unless COLOR_ENABLED
lines = err.source\lines!
for i=err_linenum-context,err_linenum-1
if line = lines[i]
- err_msg ..= "\n\027[2m#{fmt_str\format(i)}\027[0m#{line}\027[0m"
+ err_msg ..= "\n"..C('dim', fmt_str\format(i))..line
if err_line
before = err_line\sub(1, err_linepos-1)
during = err_line\sub(err_linepos,err_linepos+err_size-1)
after = err_line\sub(err_linepos+err_size, -1)
- err_line = "\027[0m#{before}\027[41;30m#{during}#{nl_indicator}\027[0m#{after}"
- err_msg ..= "\n\027[2m#{fmt_str\format(err_linenum)}#{err_line}\027[0m"
+ err_line = before..C('black on red', during..nl_indicator)..after
+ err_msg ..= "\n"..C('dim', fmt_str\format(err_linenum))..err_line
_, err_linenum_end, err_linepos_end = err.source\line_info_at(err.stop)
err_linenum_end or= err_linenum
if err_linenum_end == err_linenum
@@ -46,22 +48,24 @@ format_error = (err)->
if line = lines[i]
if i == err_linenum_end
during, after = line\sub(1,err_linepos_end-1), line\sub(err_linepos_end,-1)
- err_msg ..= "\n\027[2m#{fmt_str\format(i)}\027[0;41;30m#{during}\027[0m#{after}"
+ err_msg ..= "\n"..C('dim', fmt_str\format(i))..C('black on red', during)..after
else
- err_msg ..= "\n\027[2m#{fmt_str\format(i)}\027[0;41;30m#{line}\027[0m"
+ err_msg ..= "\n"..C('dim', fmt_str\format(i))..C('black on red', line)
if i > err_linenum+1 + 5
err_msg ..= "\n ...\n"
break
box_width = 70
- err_text = "\027[47;30;1m#{" "..err.error\wrapped_to(box_width, 16)\gsub("\n", "\n\027[47;30;1m ")}"
+ err_text = C('black on white', " "..err.error\wrapped_to(box_width, 16)\gsub("\n", "\n"..C('black on white').." "))
if err.hint
- err_text ..= "\n\027[47;30;3m#{(" Suggestion: #{err.hint}")\wrapped_to(box_width, 16)\gsub("\n", "\n\027[47;30;3m ")}"
- err_msg ..= "\n\027[33;1m "..box(err_text)\gsub("\n", "\n ")
+ err_text ..= "\n"..C('italic black on white', (" Suggestion: #{err.hint}")\wrapped_to(box_width, 16)\gsub("\n", "\n"..C('italic black on white').." "))
+ err_msg ..= "\n "..box(err_text)\gsub("\n", "\n ")
+ err_msg ..= "\n" unless COLOR_ENABLED
for i=err_linenum_end+1,err_linenum_end+context
if line = lines[i]
- err_msg ..= "\n\027[2m#{fmt_str\format(i)}\027[0m#{line}\027[0m"
+ err_msg ..= "\n"..C('dim', fmt_str\format(i))..line
+ err_msg ..= "\n" unless COLOR_ENABLED
return err_msg
return format_error