+janet:3:> (sql/eval db `CREATE TABLE customers(id INTEGER PRIMARY KEY, name TEXT);`)
+@[]
+janet:4:> (sql/eval db `INSERT INTO customers VALUES(:id, :name);` {:name "John" :id 12345})
+@[]
+janet:5:> (sql/eval db `SELECT * FROM customers;`)
+@[{"id" 12345 "name" "John"}]
+```
+
+Finally, close the database connection when done with it.
+
+```
+janet:6:> (sql/close db)
+nil
+```
diff --git a/doc/The-Janet-Abstract-Machine-Bytecode.md b/doc/The-Janet-Abstract-Machine-Bytecode.md
new file mode 100644
index 00000000..e97f9568
--- /dev/null
+++ b/doc/The-Janet-Abstract-Machine-Bytecode.md
@@ -0,0 +1,238 @@
+The Janet language is implemented on top of an abstract machine (AM). The compiler
+converts Janet data structures to this bytecode, which can then be efficiently executed
+from inside a C program. To understand the janet bytecode, it is useful to understand
+the abstractions used inside the Janet AM, as well as the C types used to implement these
+features.
+
+## The Stack = The Fiber
+
+A Janet Fiber is the type used to represent multiple concurrent processes
+in janet. It is basically a wrapper around the idea of a stack. The stack is
+divided into a number of stack frames (`JanetStackFrame *` in C), each of which
+contains information such as the function that created the stack frame,
+the program counter for the stack frame, a pointer to the previous frame,
+and the size of the frame. Each stack frame also is paired with a number
+registers.
+
+```
+X: Slot
+
+X
+X - Stack Top, for next function call.
+-----
+Frame next
+-----
+X
+X
+X
+X
+X
+X
+X - Stack 0
+-----
+Frame 0
+-----
+X
+X
+X - Stack -1
+-----
+Frame -1
+-----
+X
+X
+X
+X
+X - Stack -2
+-----
+Frame -2
+-----
+...
+...
+...
+-----
+Bottom of stack
+```
+
+Fibers also have an incomplete stack frame for the next function call on top
+of their stacks. Making a function call involves pushing arguments to this
+temporary stack, and then invoking either the CALL or TCALL instructions.
+Arguments for the next function call are pushed via the PUSH, PUSH2, PUSH3, and
+PUSHA instructions. The stack of a fiber will grow as large as needed, although by
+default janet will limit the maximum size of a fiber's stack.
+The maximum stack size can be modified on a per fiber basis.
+
+The slots in the stack are exposed as virtual registers to instructions. They
+can hold any Janet value.
+
+## Closures
+
+All functions in janet are closures; they combine some bytecode instructions
+with 0 or more environments. In the C source, a closure (hereby the same as
+a function) is represented by the type `JanetFunction *`. The bytecode instruction
+part of the function is represented by `JanetFuncDef *`, and a function environment
+is represented with `JanetFuncEnv *`.
+
+The function definition part of a function (the 'bytecode' part, `JanetFuncDef *`),
+we also store various metadata about the function which is useful for debugging,
+as well as constants referenced by the function.
+
+## C Functions
+
+Janet uses C functions to bridge to native code. A C function
+(`JanetCFunction *` in C) is a C function pointer that can be called like
+a normal janet closure. From the perspective of the bytecode instruction set, there is no difference
+in invoking a C function and invoking a normal janet function.
+
+## Bytecode Format
+
+Janet bytecode presents an interface to a virtual machine with a large number
+of identical registers that can hold any Janet value (`Janet *` in C). Most instructions
+have a destination register, and 1 or 2 source register. Registers are simply
+named with positive integers.
+
+Each instruction is a 32 bit integer, meaning that the instruction set is a constant
+width RISC instruction set like MIPS. The opcode of each instruction is the least significant
+byte of the instruction. The highest bit of
+this leading byte is reserved for debugging purpose, so there are 128 possible opcodes encodable
+with this scheme. Not all of these possible opcode are defined, and will trap the interpreter
+and emit a debug signal. Note that this mean an unknown opcode is still valid bytecode, it will
+just put the interpreter into a debug state when executed.
+
+```
+X - Payload bits
+O - Opcode bits
+
+ 4 3 2 1
++----+----+----+----+
+| XX | XX | XX | OO |
++----+----+----+----+
+```
+
+8 bits for the opcode leaves 24 bits for the payload, which may or may not be utilized.
+There are a few instruction variants that divide these payload bits.
+
+* 0 arg - Used for noops, returning nil, or other instructions that take no
+ arguments. The payload is essentially ignored.
+* 1 arg - All payload bits correspond to a single value, usually a signed or unsigned integer.
+ Used for instructions of 1 argument, like returning a value, yielding a value to the parent fiber,
+ or doing a (relative) jump.
+* 2 arg - Payload is split into byte 2 and bytes 3 and 4.
+ The first argument is the 8 bit value from byte 2, and the second argument is the 16 bit value
+ from bytes 3 and 4 (`instruction >> 16`). Used for instructions of two arguments, like move, normal
+ function calls, conditionals, etc.
+* 3 arg - Bytes 2, 3, and 4 each correspond to an 8 bit argument.
+ Used for arithmetic operations, emitting a signal, etc.
+
+These instruction variants can be further refined based on the semantics of the arguments.
+Some instructions may treat an argument as a slot index, while other instructions
+will treat the argument as a signed integer literal, and index for a constant, an index
+for an environment, or an unsigned integer.
+
+## Instruction Reference
+
+A listing of all opcode values can be found in src/include/janet/janetopcodes.h. The janet assembly
+short names can be found src/assembler/asm.c. In this document, we will refer to the instructions
+by their short names as presented to the assembler rather than their numerical values.
+
+Each instruction is also listed with a signature, which are the arguments the instruction
+expects. There are a handful of instruction signatures, which combine the arity and type
+of the instruction. The assembler does not
+do any typechecking per closure, but does prevent jumping to invalid instructions and
+failure to return or error.
+
+### Notation
+
+* The $ prefix indicates that a instruction parameter is acting as a virtual register (slot).
+ If a parameter does not have the $ suffix in the description, it is acting as some kind
+ of literal (usually an unsigned integer for indexes, and a signed integer for literal integers).
+
+* Some operators in the description have the suffix 'i' or 'r'. These indicate
+ that these operators correspond to integers or real numbers only, respectively. All
+ bitwise operators and bit shifts only work with integers.
+
+* The `>>>` indicates unsigned right shift, as in Java. Because all integers in janet are
+ signed, we differentiate the two kinds of right bit shift.
+
+* The 'im' suffix in the instruction name is short for immediate. The 'i' suffix is short for integer,
+ and the 'r' suffix is short for real.
+
+### Reference Table
+
+| Instruction | Signature | Description |
+| ----------- | --------------------------- | --------------------------------- |
+| `add` | `(add dest lhs rhs)` | $dest = $lhs + $rhs |
+| `addi` | `(addi dest lhs rhs)` | $dest = $lhs +i $rhs |
+| `addim` | `(addim dest lhs im)` | $dest = $lhs +i im |
+| `addr` | `(addr dest lhs rhs)` | $dest = $lhs +r $rhs |
+| `band` | `(band dest lhs rhs)` | $dest = $lhs & $rhs |
+| `bnot` | `(bnot dest operand)` | $dest = ~$operand |
+| `bor` | `(bor dest lhs rhs)` | $dest = $lhs | $rhs |
+| `bxor` | `(bxor dest lhs rhs)` | $dest = $lhs ^ $rhs |
+| `call` | `(call dest callee)` | $dest = call($callee, args) |
+| `clo` | `(clo dest index)` | $dest = closure(defs[$index]) |
+| `cmp` | `(cmp dest lhs rhs)` | $dest = janet\_compare($lhs, $rhs) |
+| `div` | `(div dest lhs rhs)` | $dest = $lhs / $rhs |
+| `divi` | `(divi dest lhs rhs)` | $dest = $lhs /i $rhs |
+| `divim` | `(divim dest lhs im)` | $dest = $lhs /i im |
+| `divr` | `(divr dest lhs rhs)` | $dest = $lhs /r $rhs |
+| `eq` | `(eq dest lhs rhs)` | $dest = $lhs == $rhs |
+| `eqi` | `(eqi dest lhs rhs)` | $dest = $lhs ==i $rhs |
+| `eqim` | `(eqim dest lhs im)` | $dest = $lhs ==i im |
+| `eqr` | `(eqr dest lhs rhs)` | $dest = $lhs ==r $rhs |
+| `err` | `(err message)` | Throw error $message. |
+| `get` | `(get dest ds key)` | $dest = $ds[$key] |
+| `geti` | `(geti dest ds index)` | $dest = $ds[index] |
+| `gt` | `(gt dest lhs rhs)` | $dest = $lhs > $rhs |
+| `gti` | `(gti dest lhs rhs)` | $dest = $lhs \>i $rhs |
+| `gtim` | `(gtim dest lhs im)` | $dest = $lhs \>i im |
+| `gtr` | `(gtr dest lhs rhs)` | $dest = $lhs \>r $rhs |
+| `gter` | `(gter dest lhs rhs)` | $dest = $lhs >=r $rhs |
+| `jmp` | `(jmp label)` | pc = label, pc += offset |
+| `jmpif` | `(jmpif cond label)` | if $cond pc = label else pc++ |
+| `jmpno` | `(jmpno cond label)` | if $cond pc++ else pc = label |
+| `ldc` | `(ldc dest index)` | $dest = constants[index] |
+| `ldf` | `(ldf dest)` | $dest = false |
+| `ldi` | `(ldi dest integer)` | $dest = integer |
+| `ldn` | `(ldn dest)` | $dest = nil |
+| `lds` | `(lds dest)` | $dest = current closure (self) |
+| `ldt` | `(ldt dest)` | $dest = true |
+| `ldu` | `(ldu dest env index)` | $dest = envs[env][index] |
+| `len` | `(len dest ds)` | $dest = length(ds) |
+| `lt` | `(lt dest lhs rhs)` | $dest = $lhs < $rhs |
+| `lti` | `(lti dest lhs rhs)` | $dest = $lhs \> $rhs |
+| `srim` | `(srim dest lhs shamt)` | $dest = $lhs >> shamt |
+| `sru` | `(sru dest lhs rhs)` | $dest = $lhs >>> $rhs |
+| `sruim` | `(sruim dest lhs shamt)` | $dest = $lhs >>> shamt |
+| `sub` | `(sub dest lhs rhs)` | $dest = $lhs - $rhs |
+| `tcall` | `(tcall callee)` | Return call($callee, args) |
+| `tchck` | `(tcheck slot types)` | Assert $slot does matches types |
+
diff --git a/doc/gendoc.janet b/doc/gendoc.janet
new file mode 100644
index 00000000..1d1c273e
--- /dev/null
+++ b/doc/gendoc.janet
@@ -0,0 +1,97 @@
+# Generate documentation
+
+(def- prelude
+```
+
+
+
+
+Janet Language Documentation
+
+
+
+```)
+
+(def- postlude
+```
+
+```)
+
+(def- escapes
+ {10 "
"
+ 09 " "
+ 38 "&"
+ 60 "<"
+ 62 ">"
+ 34 """
+ 39 "'"
+ 47 "/"})
+
+(defn- trim-lead
+ "Trim leading newlines"
+ [str]
+ (var i 0)
+ (while (= 10 str.i) (++ i))
+ (string/slice str i))
+
+(defn- html-escape
+ "Escape special characters for HTML encoding."
+ [str]
+ (def buf @"")
+ (loop [byte :in str]
+ (if-let [rep escapes.byte]
+ (buffer/push-string buf rep)
+ (buffer/push-byte buf byte)))
+ buf)
+
+(defn- make-title
+ "Generate title"
+ []
+ (string "Janet Core API
"
+ "Version " janet/version "-" janet/build "
"
+ "Generated "
+ (string/number (os/time) :f 0 20)
+ " seconds after epoch
"
+ "
"))
+
+(defn- emit-item
+ "Generate documentation for one entry."
+ [key env-entry]
+ (let [{:macro macro
+ :value val
+ :ref ref
+ :source-map sm
+ :doc docstring} env-entry
+ binding-type (cond
+ macro :macro
+ ref (string :var " (" (type ref.0) ")")
+ (type val))
+ source-ref (if-let [[path start end] sm]
+ (string "" path " (" start ":" end ")")
+ "")]
+ (string "" (html-escape key) "
\n"
+ "" binding-type "\n"
+ "" (trim-lead (html-escape docstring)) "
\n"
+ source-ref)))
+
+# Generate parts and print them to stdout
+(def parts (seq [[k entry]
+ :in (sort (pairs (table/getproto _env)))
+ :when (and entry:doc (not entry:private))]
+ (emit-item k entry)))
+(print
+ prelude
+ (make-title)
+ ;(interpose "
\n" parts)
+ postlude)
diff --git a/examples/3sum.janet b/examples/3sum.janet
index 21bac9bd..9b3c1d6a 100644
--- a/examples/3sum.janet
+++ b/examples/3sum.janet
@@ -11,4 +11,4 @@
(def k (get tab (- 0 s@i s@j)))
(when (and k (not= k i) (not= k j) (not= i j))
(put solutions {i true j true k true} true))))
- (map keys (keys solution)))
+ (map keys (keys solution)))
\ No newline at end of file
diff --git a/lib/colors.janet b/examples/colors.janet
similarity index 100%
rename from lib/colors.janet
rename to examples/colors.janet
diff --git a/lib/lazyseqs.janet b/examples/lazyseqs.janet
similarity index 95%
rename from lib/lazyseqs.janet
rename to examples/lazyseqs.janet
index d9d556a7..e024e44b 100644
--- a/lib/lazyseqs.janet
+++ b/examples/lazyseqs.janet
@@ -18,12 +18,12 @@
(if ,loaded
,state
(do
- (:= ,loaded true)
- (:= ,state (do ;forms)))))))
+ (set ,loaded true)
+ (set ,state (do ;forms)))))))
# Use tuples instead of structs to save memory
-(def HEAD :private 0)
-(def TAIL :private 1)
+(def- HEAD 0)
+(def- TAIL 1)
(defn empty-seq
"The empty sequence."
diff --git a/examples/life.janet b/examples/life.janet
index 846acd22..3402a969 100644
--- a/examples/life.janet
+++ b/examples/life.janet
@@ -16,7 +16,7 @@
(def cell-set (frequencies state))
(def neighbor-set (frequencies (mapcat neighbors state)))
(seq [coord :keys neighbor-set
- :let [count neighbor-set@coord]
+ :let [count neighbor-set.coord]
:when (or (= count 3) (and (get cell-set coord) (= count 2)))]
coord))
@@ -24,7 +24,7 @@
"Draw cells in the game of life from (x1, y1) to (x2, y2)"
[state x1 y1 x2 y2]
(def cellset @{})
- (each cell state (:= cellset@cell true))
+ (each cell state (set cellset.cell true))
(loop [x :range [x1 (+ 1 x2)]
:after (print)
y :range [y1 (+ 1 y2)]]
@@ -40,4 +40,4 @@
(for i 0 20
(print "generation " i)
(draw *state* -7 -7 7 7)
- (:= *state* (tick *state*)))
+ (set *state* (tick *state*)))
diff --git a/examples/primes.janet b/examples/primes.janet
index 6cf80693..38cc91fe 100644
--- a/examples/primes.janet
+++ b/examples/primes.janet
@@ -9,6 +9,6 @@
(def len (length list))
(for j 0 len
(def trial (get list j))
- (if (zero? (% i trial)) (:= isprime? false)))
+ (if (zero? (% i trial)) (set isprime? false)))
(if isprime? (array/push list i)))
list)
diff --git a/grammar/janet.tmLanguage b/grammar/janet.tmLanguage
new file mode 100644
index 00000000..79faa465
--- /dev/null
+++ b/grammar/janet.tmLanguage
@@ -0,0 +1,335 @@
+
+
+
+
+ fileTypes
+
+ janet
+
+ foldingStartMarker
+ \{
+ foldingStopMarker
+ \}
+ foldingStartMarker
+ \[
+ foldingStopMarker
+ \]
+ foldingStartMarker
+ \(
+ foldingStopMarker
+ \)
+ keyEquivalent
+ ^~L
+ name
+ Janet
+ patterns
+
+
+ include
+ #all
+
+
+ repository
+
+ all
+
+ patterns
+
+
+ include
+ #comment
+
+
+ include
+ #parens
+
+
+ include
+ #brackets
+
+
+ include
+ #braces
+
+
+ include
+ #readermac
+
+
+ include
+ #string
+
+
+ include
+ #longstring
+
+
+ include
+ #literal
+
+
+ include
+ #corelib
+
+
+ include
+ #r-number
+
+
+ include
+ #dec-number
+
+
+ include
+ #hex-number
+
+
+ include
+ #keysym
+
+
+ include
+ #symbol
+
+
+
+ comment
+
+ captures
+
+ 1
+
+ name
+ punctuation.definition.comment.janet
+
+
+ match
+ (#).*$
+ name
+ comment.line.janet
+
+ braces
+
+ begin
+ (@?{)
+ captures
+
+ 1
+
+ name
+ punctuation.definition.braces.begin.janet
+
+
+ end
+ (})
+ captures
+
+ 1
+
+ name
+ punctuation.definition.braces.end.janet
+
+
+ patterns
+
+
+ include
+ #all
+
+
+
+ brackets
+
+ begin
+ (@?\[)
+ captures
+
+ 1
+
+ name
+ punctuation.definition.brackets.begin.janet
+
+
+ end
+ (\])
+ captures
+
+ 1
+
+ name
+ punctuation.definition.brackets.end.janet
+
+
+ patterns
+
+
+ include
+ #all
+
+
+
+ parens
+
+ begin
+ (@?\()
+ captures
+
+ 1
+
+ name
+ punctuation.definition.parens.begin.janet
+
+
+ end
+ (\))
+ captures
+
+ 1
+
+ name
+ punctuation.definition.parens.end.janet
+
+
+ patterns
+
+
+ include
+ #all
+
+
+
+ readermac
+
+ match
+ [\'\~\;\,]
+ name
+ punctuation.other.janet
+
+
+ literal
+
+ match
+ (?<![\.:\w_\-=!@\$%^&?|\\/<>*])(true|false|nil)(?![\.:\w_\-=!@\$%^&?|\\/<>*])
+ name
+ constant.language.janet
+
+ corelib
+
+ match
+ (?<![\.:\w_\-=!@\$%^&?|\\/<>*])(def|do|fn|if|quasiquote|quote|set|splice|unquote|var|while|%|%=|\*|\*=|\*doc\-width\*|\*env\*|\+|\+\+|\+=|\-|\-\-|\-=|\->|\->>|/|/=|<|<=|=|==|>|>=|_env|abstract\?|all|all\-symbols|allsyms|and|apply|array|array/concat|array/ensure|array/insert|array/new|array/peek|array/pop|array/push|array/slice|array\?|asm|band|blshift|bnot|boolean\?|bor|brshift|brushift|buffer|buffer/clear|buffer/new|buffer/popn|buffer/push\-byte|buffer/push\-integer|buffer/push\-string|buffer/slice|buffer\?|bxor|bytes\?|callable\?|case|cfunction\?|comment|comp|compile|complement|cond|coro|count|debug|debug/arg\-stack|debug/break|debug/fbreak|debug/lineage|debug/stack|debug/unbreak|debug/unfbreak|dec|deep\-not=|deep=|def\-|default|defglobal|defmacro|defmacro\-|defn|defn\-|describe|dictionary\?|disasm|distinct|doc|doc\*|doc\-format|drop\-until|drop\-while|each|empty\?|env\-lookup|error|eval|eval\-string|even\?|every\?|extreme|false\?|fiber/current|fiber/maxstack|fiber/new|fiber/setmaxstack|fiber/status|fiber\?|file/close|file/flush|file/open|file/popen|file/read|file/seek|file/write|filter|find|find\-index|first|flatten|flatten\-into|for|frequencies|function\?|gccollect|gcinterval|gcsetinterval|generate|gensym|get|getline|hash|idempotent\?|identity|if\-let|if\-not|import|import\*|inc|indexed\?|int|integer\?|interleave|interpose|invert|janet/build|janet/version|juxt|juxt\*|keep|keys|keyword\?|kvs|last|length|let|loop|macex|macex1|make\-env|map|mapcat|marshal|match|match\-1|math/acos|math/asin|math/atan|math/ceil|math/cos|math/e|math/exp|math/floor|math/inf|math/log|math/log10|math/pi|math/pow|math/random|math/seedrandom|math/sin|math/sqrt|math/tan|max|max\-order|merge|merge\-into|min|min\-order|module/find|module/native\-paths|module/paths|native|neg\?|next|nil\?|not|not=|not==|number\?|odd\?|one\?|or|order<|order<=|order>|order>=|os/clock|os/cwd|os/execute|os/exit|os/getenv|os/setenv|os/shell|os/sleep|os/time|os/which|pairs|parser/byte|parser/consume|parser/error|parser/flush|parser/new|parser/produce|parser/state|parser/status|parser/where|partial|pos\?|print|process/args|product|put|range|real|real\?|reduce|repl|require|resume|reverse|run\-context|scan\-integer|scan\-number|scan\-real|sentinel|seq|some|sort|sorted|status\-pp|stderr|stdin|stdout|string|string/ascii\-lower|string/ascii\-upper|string/bytes|string/check\-set|string/find|string/find\-all|string/from\-bytes|string/join|string/number|string/pretty|string/repeat|string/replace|string/replace\-all|string/reverse|string/slice|string/split|string\?|struct|struct\?|sum|symbol|symbol\?|table|table/getproto|table/new|table/rawget|table/setproto|table/to\-struct|table\?|take\-until|take\-while|true\?|tuple|tuple/append|tuple/prepend|tuple/slice|tuple\?|type|unless|unmarshal|update|values|varglobal|when|when\-let|with\-idemp|yield|zero\?|zipcoll)(?![\.:\w_\-=!@\$%^&?|\\/<>*])
+ name
+ keyword.control.janet
+
+ keysym
+
+ match
+ (?<![\.:\w_\-=!@\$%^&?|\\/<>*]):[\.:\w_\-=!@\$%^&?|\\/<>*]*
+ name
+ constant.keyword.janet
+
+ symbol
+
+ match
+ (?<![\.:\w_\-=!@\$%^&?|\\/<>*])[\.a-zA-Z_\-=!@\$%^&?|\\/<>*][\.:\w_\-=!@\$%^&?|\\/<>*]*
+ name
+ variable.other.janet
+
+ hex-number
+
+ match
+ (?<![\.:\w_\-=!@\$%^&?|\\/<>*])[-+]?0x([_\da-fA-F]+|[_\da-fA-F]+\.[_\da-fA-F]*|\.[_\da-fA-F]+)(&[+-]?[\da-fA-F]+)?(?![\.:\w_\-=!@\$%^&?|\\/<>*])
+ name
+ constant.numeric.hex.janet
+
+ dec-number
+
+ match
+ (?<![\.:\w_\-=!@\$%^&?|\\/<>*])[-+]?([_\d]+|[_\d]+\.[_\d]*|\.[_\d]+)([eE&][+-]?[\d]+)?(?![\.:\w_\-=!@\$%^&?|\\/<>*])
+ name
+ constant.numeric.decimal.janet
+
+ r-number
+
+ match
+ (?<![\.:\w_\-=!@\$%^&?|\\/<>*])[-+]?\d\d?r([_\w]+|[_\w]+\.[_\w]*|\.[_\w]+)(&[+-]?[\w]+)?(?![\.:\w_\-=!@\$%^&?|\\/<>*])
+ name
+ constant.numeric.decimal.janet
+
+ string
+
+ begin
+ (@?")
+ beginCaptures
+
+ 1
+
+ name
+ punctuation.definition.string.begin.janet
+
+
+ end
+ (")
+ endCaptures
+
+ 1
+
+ name
+ punctuation.definition.string.end.janet
+
+
+ name
+ string.quoted.double.janet
+ patterns
+
+
+ match
+ (\\[ne0zft"\\']|\\x[0-9a-fA-F][0-9a-fA-f])
+ name
+ constant.character.escape.janet
+
+
+
+ longstring
+
+ begin
+ (@?)(`+)
+ beginCaptures
+
+ 1
+
+ name
+ punctuation.definition.string.begin.janet
+
+ 2
+
+ name
+ punctuation.definition.string.begin.janet
+
+
+ end
+ \2
+ endCaptures
+
+ 1
+
+ name
+ punctuation.definition.string.end.janet
+
+
+ name
+ string.quoted.triple.janet
+
+ nomatch
+
+ match
+ \S+
+ name
+ invalid.illegal.janet
+
+
+ scopeName
+ source.janet
+ uuid
+ 3743190f-20c4-44d0-8640-6611a983296b
+
+
diff --git a/grammar/tmcorelib.janet b/grammar/tmcorelib.janet
new file mode 100644
index 00000000..69f05291
--- /dev/null
+++ b/grammar/tmcorelib.janet
@@ -0,0 +1,30 @@
+# Helper to generate core library mappings for janet
+
+(def allsyms (all-symbols))
+
+(def- escapes
+ {(get "|" 0) `\|`
+ (get "-" 0) `\-`
+ (get "+" 0) `\+`
+ (get "*" 0) `\*`
+ (get "^" 0) `\^`
+ (get "$" 0) `\$`
+ (get "?" 0) `\?`
+ 38 "&"
+ 60 "<"
+ 62 ">"
+ 34 """
+ 39 "'"
+ 47 "/"})
+
+(defn- escape
+ "Escape special characters for HTML and regex encoding."
+ [str]
+ (def buf @"")
+ (loop [byte :in str]
+ (if-let [rep escapes.byte]
+ (buffer/push-string buf rep)
+ (buffer/push-byte buf byte)))
+ buf)
+
+(print (string/join (map escape allsyms) "|"))
diff --git a/natives/json/json.c b/natives/json/json.c
index c11f92e1..4f01af33 100644
--- a/natives/json/json.c
+++ b/natives/json/json.c
@@ -588,7 +588,7 @@ static int json_encode(JanetArgs args) {
static const JanetReg cfuns[] = {
{"encode", json_encode,
- "(json/encode x)\n\n"
+ "(json/encode x [,tab [,newline]])\n\n"
"Encodes a janet value in JSON (utf-8)."
},
{"decode", json_decode,
diff --git a/src/core/asm.c b/src/core/asm.c
index 050aae26..3633360f 100644
--- a/src/core/asm.c
+++ b/src/core/asm.c
@@ -710,8 +710,8 @@ static JanetAssembleResult janet_asm1(JanetAssembler *parent, Janet source, int
if (!janet_checktype(tup[1], JANET_INTEGER)) {
janet_asm_error(&a, "expected integer");
}
- mapping.line = janet_unwrap_integer(tup[0]);
- mapping.column = janet_unwrap_integer(tup[1]);
+ mapping.start = janet_unwrap_integer(tup[0]);
+ mapping.end = janet_unwrap_integer(tup[1]);
def->sourcemap[i] = mapping;
}
}
@@ -876,8 +876,8 @@ Janet janet_disasm(JanetFuncDef *def) {
for (i = 0; i < def->bytecode_length; i++) {
Janet *t = janet_tuple_begin(2);
JanetSourceMapping mapping = def->sourcemap[i];
- t[0] = janet_wrap_integer(mapping.line);
- t[1] = janet_wrap_integer(mapping.column);
+ t[0] = janet_wrap_integer(mapping.start);
+ t[1] = janet_wrap_integer(mapping.end);
sourcemap->data[i] = janet_wrap_tuple(janet_tuple_end(t));
}
sourcemap->count = def->bytecode_length;
diff --git a/src/core/bytecode.c b/src/core/bytecode.c
index 83106baf..0112e605 100644
--- a/src/core/bytecode.c
+++ b/src/core/bytecode.c
@@ -125,10 +125,10 @@ int32_t janet_verify(JanetFuncDef *def) {
for (i = 0; i < def->bytecode_length; i++) {
uint32_t instr = def->bytecode[i];
/* Check for invalid instructions */
- if ((instr & 0xFF) >= JOP_INSTRUCTION_COUNT) {
+ if ((instr & 0x7F) >= JOP_INSTRUCTION_COUNT) {
return 3;
}
- enum JanetInstructionType type = janet_instructions[instr & 0xFF];
+ enum JanetInstructionType type = janet_instructions[instr & 0x7F];
switch (type) {
case JINT_0:
continue;
diff --git a/src/core/compile.c b/src/core/compile.c
index e67da663..fd711356 100644
--- a/src/core/compile.c
+++ b/src/core/compile.c
@@ -462,9 +462,9 @@ static int macroexpand1(
if (janet_tuple_length(form) == 0)
return 0;
/* Source map - only set when we get a tuple */
- if (janet_tuple_sm_line(form) > 0) {
- c->current_mapping.line = janet_tuple_sm_line(form);
- c->current_mapping.column = janet_tuple_sm_col(form);
+ if (janet_tuple_sm_start(form) >= 0) {
+ c->current_mapping.start = janet_tuple_sm_start(form);
+ c->current_mapping.end = janet_tuple_sm_end(form);
}
if (!janet_checktype(form[0], JANET_SYMBOL))
return 0;
@@ -575,13 +575,13 @@ JanetSlot janetc_value(JanetFopts opts, Janet x) {
if (c->result.status == JANET_COMPILE_ERROR)
return janetc_cslot(janet_wrap_nil());
- c->current_mapping = last_mapping;
if (opts.flags & JANET_FOPTS_TAIL)
ret = janetc_return(opts.compiler, ret);
if (opts.flags & JANET_FOPTS_HINT) {
janetc_copy(opts.compiler, opts.hint, ret);
ret = opts.hint;
}
+ c->current_mapping = last_mapping;
opts.compiler->recursion_guard++;
return ret;
}
@@ -648,15 +648,15 @@ static void janetc_init(JanetCompiler *c, JanetTable *env, const uint8_t *where)
c->recursion_guard = JANET_RECURSION_GUARD;
c->env = env;
c->source = where;
- c->current_mapping.line = 0;
- c->current_mapping.column = 0;
+ c->current_mapping.start = -1;
+ c->current_mapping.end = -1;
/* Init result */
c->result.error = NULL;
c->result.status = JANET_COMPILE_OK;
c->result.funcdef = NULL;
c->result.macrofiber = NULL;
- c->result.error_mapping.line = 0;
- c->result.error_mapping.column = 0;
+ c->result.error_mapping.start = -1;
+ c->result.error_mapping.end = -1;
}
/* Deinitialize a compiler struct */
@@ -717,8 +717,8 @@ static int cfun(JanetArgs args) {
} else {
t = janet_table(4);
janet_table_put(t, janet_csymbolv(":error"), janet_wrap_string(res.error));
- janet_table_put(t, janet_csymbolv(":line"), janet_wrap_integer(res.error_mapping.line));
- janet_table_put(t, janet_csymbolv(":column"), janet_wrap_integer(res.error_mapping.column));
+ janet_table_put(t, janet_csymbolv(":start"), janet_wrap_integer(res.error_mapping.start));
+ janet_table_put(t, janet_csymbolv(":end"), janet_wrap_integer(res.error_mapping.end));
if (res.macrofiber) {
janet_table_put(t, janet_csymbolv(":fiber"), janet_wrap_fiber(res.macrofiber));
}
diff --git a/src/core/core.janet b/src/core/core.janet
index b2b3a1a0..7c4e5057 100644
--- a/src/core/core.janet
+++ b/src/core/core.janet
@@ -25,7 +25,7 @@
i
(do
(if (= t :string)
- (:= docstr ith)
+ (set docstr ith)
(array/push modifiers ith))
(if (< i len) (recur (+ i 1)))))))
(def start (fstart 0))
@@ -37,7 +37,7 @@
(while (< index arglen)
(buffer/push-string buf " ")
(string/pretty args.index 4 buf)
- (:= index (+ index 1)))
+ (set index (+ index 1)))
(array/push modifiers (string buf ")\n\n" docstr))
# Build return value
~(def ,name ,;modifiers (fn ,name ,;(tuple/slice more start)))))
@@ -84,25 +84,24 @@
(defn neg? "Check if x is less than 0." [x] (< x 0))
(defn one? "Check if x is equal to 1." [x] (== x 1))
(defn integer? "Check if x is an integer." [x] (= (type x) :integer))
-(defn real? [x] "Check if x is a real number." (= (type x) :real))
+(defn real? "Check if x is a real number." [x] (= (type x) :real))
(defn number? "Check if x is a number." [x]
(def t (type x))
(if (= t :integer) true (= t :real)))
(defn fiber? "Check if x is a fiber." [x] (= (type x) :fiber))
(defn string? "Check if x is a string." [x] (= (type x) :string))
(defn symbol? "Check if x is a symbol." [x] (= (type x) :symbol))
-(defn keyword? "Check if x is a keyword style symbol."
- [x]
+(defn keyword? "Check if x is a keyword style symbol." [x]
(if (not= (type x) :symbol) nil (= 58 x.0)))
(defn buffer? "Check if x is a buffer." [x] (= (type x) :buffer))
-(defn function? "Check if x is a function (not a cfunction)."
- [x] (= (type x) :function))
+(defn function? "Check if x is a function (not a cfunction)." [x]
+ (= (type x) :function))
(defn cfunction? "Check if x a cfunction." [x] (= (type x) :cfunction))
-(defn table? [x] "Check if x a table." (= (type x) :table ))
-(defn struct? [x] "Check if x a struct." (= (type x) :struct))
-(defn array? [x] "Check if x is an array." (= (type x) :array))
-(defn tuple? [x] "Check if x is a tuple." (= (type x) :tuple))
-(defn boolean? [x] "Check if x is a boolean." (= (type x) :boolean))
+(defn table? "Check if x a table." [x] (= (type x) :table ))
+(defn struct? "Check if x a struct." [x] (= (type x) :struct))
+(defn array? "Check if x is an array." [x] (= (type x) :array))
+(defn tuple? "Check if x is a tuple." [x] (= (type x) :tuple))
+(defn boolean? "Check if x is a boolean." [x] (= (type x) :boolean))
(defn bytes? "Check if x is a string, symbol, or buffer." [x]
(def t (type x))
(if (= t :string) true (if (= t :symbol) true (= t :buffer))))
@@ -132,9 +131,9 @@
(defmacro with-idemp
"Return janet code body that has been prepended
- with a binding of form to atom. If form is a non-
- idempotent form (a function call, etc.), make sure the resulting
- code will only call evaluate once, even if body contains multiple
+ with a binding of form to atom. If form is a non-idempotent
+ form (a function call, etc.), make sure the resulting
+ code will only evaluate once, even if body contains multiple
copies of binding. In body, use binding instead of form."
[binding form & body]
(def $result (gensym))
@@ -147,22 +146,16 @@
,$result
(tuple 'do (tuple 'def ,binding ,$form) ,$result))))
-# C style macros and functions for imperative sugar
+# C style macros and functions for imperative sugar. No bitwise though.
(defn inc "Returns x + 1." [x] (+ x 1))
(defn dec "Returns x - 1." [x] (- x 1))
-(defmacro ++ "Increments the var x by 1." [x] ~(:= ,x (,+ ,x ,1)))
-(defmacro -- "Decrements the var x by 1." [x] ~(:= ,x (,- ,x ,1)))
-(defmacro += "Increments the var x by n." [x n] ~(:= ,x (,+ ,x ,n)))
-(defmacro -= "Decrements the vat x by n." [x n] ~(:= ,x (,- ,x ,n)))
-(defmacro *= "Shorthand for (:= x (* x n))." [x n] ~(:= ,x (,* ,x ,n)))
-(defmacro /= "Shorthand for (:= x (/ x n))." [x n] ~(:= ,x (,/ ,x ,n)))
-(defmacro %= "Shorthand for (:= x (% x n))." [x n] ~(:= ,x (,% ,x ,n)))
-(defmacro &= "Shorthand for (:= x (& x n))." [x n] ~(:= ,x (,& ,x ,n)))
-(defmacro |= "Shorthand for (:= x (| x n))." [x n] ~(:= ,x (,| ,x ,n)))
-(defmacro ^= "Shorthand for (:= x (^ x n))." [x n] ~(:= ,x (,^ ,x ,n)))
-(defmacro >>= "Shorthand for (:= x (>> x n))." [x n] ~(:= ,x (,>> ,x ,n)))
-(defmacro <<= "Shorthand for (:= x (<< x n))." [x n] ~(:= ,x (,<< ,x ,n)))
-(defmacro >>>= "Shorthand for (:= x (>>> x n))." [x n] ~(:= ,x (,>>> ,x ,n)))
+(defmacro ++ "Increments the var x by 1." [x] ~(set ,x (,+ ,x ,1)))
+(defmacro -- "Decrements the var x by 1." [x] ~(set ,x (,- ,x ,1)))
+(defmacro += "Increments the var x by n." [x n] ~(set ,x (,+ ,x ,n)))
+(defmacro -= "Decrements the var x by n." [x n] ~(set ,x (,- ,x ,n)))
+(defmacro *= "Shorthand for (set x (* x n))." [x n] ~(set ,x (,* ,x ,n)))
+(defmacro /= "Shorthand for (set x (/ x n))." [x n] ~(set ,x (,/ ,x ,n)))
+(defmacro %= "Shorthand for (set x (% x n))." [x n] ~(set ,x (,% ,x ,n)))
(defmacro default
"Define a default value for an optional argument.
@@ -249,7 +242,7 @@
(var i len)
(while (> i 0)
(-- i)
- (:= ret (if (= ret true)
+ (set ret (if (= ret true)
forms.i
(tuple 'if forms.i ret))))
ret)
@@ -264,7 +257,7 @@
(while (> i 0)
(-- i)
(def fi forms.i)
- (:= ret (if (idempotent? fi)
+ (set ret (if (idempotent? fi)
(tuple 'if fi fi ret)
(do
(def $fi (gensym))
@@ -332,13 +325,13 @@
(tuple 'var $iter 0)
(tuple 'while
(tuple/slice spreds)
- (tuple := $iter (tuple + 1 $iter))
+ (tuple 'set $iter (tuple + 1 $iter))
sub)))
(error (string "unexpected loop predicate: " bindings)))
(case verb
:iterate (do
(def $iter (gensym))
- (def preds @['and (tuple ':= $iter object)])
+ (def preds @['and (tuple 'set $iter object)])
(def subloop (doone (+ i 3) preds))
(tuple 'do
(tuple 'var $iter nil)
@@ -358,7 +351,7 @@
(tuple 'while (tuple/slice preds)
(tuple 'def bindings $iter)
subloop
- (tuple ':= $iter (tuple + $iter inc)))))
+ (tuple 'set $iter (tuple + $iter inc)))))
:keys (do
(def $dict (gensym))
(def $iter (gensym))
@@ -370,7 +363,7 @@
(tuple 'while (tuple/slice preds)
(tuple 'def bindings $iter)
subloop
- (tuple ':= $iter (tuple next $dict $iter)))))
+ (tuple 'set $iter (tuple next $dict $iter)))))
:in (do
(def $len (gensym))
(def $i (gensym))
@@ -384,7 +377,7 @@
(tuple 'while (tuple/slice preds 0)
(tuple 'def bindings (tuple get $indexed $i))
subloop
- (tuple ':= $i (tuple + 1 $i)))))
+ (tuple 'set $i (tuple + 1 $i)))))
:generate (do
(def $fiber (gensym))
(def $yieldval (gensym))
@@ -401,7 +394,7 @@
(tuple 'while (tuple/slice preds 0)
(tuple 'def bindings $yieldval)
subloop
- (tuple := $yieldval (tuple resume $fiber)))))
+ (tuple 'set $yieldval (tuple resume $fiber)))))
(error (string "unexpected loop verb: " verb)))))))
(doone 0 nil))
@@ -434,21 +427,23 @@
(tuple fiber/new (tuple 'fn '[&] ;body)))
(defn sum
+ "Returns the sum of xs. If xs is empty, returns 0."
[xs]
(var accum 0)
(loop [x :in xs] (+= accum x))
accum)
(defn product
+ "Returns the product of xs. If xs is empty, returns 1."
[xs]
(var accum 1)
(loop [x :in xs] (*= accum x))
accum)
(defmacro if-let
- "Takes the first one or two forms in a vector and if both are true binds
- all the forms with let and evaluates the first expression else
- evaluates the second"
+ "Make mutliple bindings, anf if all are truthy,
+ evaluate the tru form. If any are false or nil, evaluate
+ the fal form. Bindings have the same syntax as the let macro."
[bindings tru fal &]
(def len (length bindings))
(if (zero? len) (error "expected at least 1 binding"))
@@ -477,8 +472,7 @@
(aux 0))
(defmacro when-let
- "Takes the first one or two forms in vector and if true binds
- all the forms with let and evaluates the body"
+ "Same as (if-let bindings (do ;body))."
[bindings & body]
~(if-let ,bindings (do ,;body)))
@@ -516,13 +510,26 @@
(var ret args.0)
(loop [i :range [0 len]]
(def v args.i)
- (if (order v ret) (:= ret v)))
+ (if (order v ret) (set ret v)))
ret))
-(defn max [& args] (extreme > args))
-(defn min [& args] (extreme < args))
-(defn max-order [& args] (extreme order> args))
-(defn min-order [& args] (extreme order< args))
+(defn max
+ "Returns the numeric maximum of the arguments."
+ [& args] (extreme > args))
+
+(defn min
+ "Returns the numeric minimum of the arguments."
+ [& args] (extreme < args))
+
+(defn max-order
+ "Returns the maximum of the arguments according to a total
+ order over all values."
+ [& args] (extreme order> args))
+
+(defn min-order
+ "Returns the minimum of the arguments according to a total
+ order over all values."
+ [& args] (extreme order< args))
(defn first
"Get the first element from an indexed data structure."
@@ -541,7 +548,7 @@
###
(def sort
- "Sort an array in-place. Uses quicksort and is not a stable sort."
+ "(sort xs [, by])\n\nSort an array in-place. Uses quicksort and is not a stable sort."
(do
(defn partition
@@ -552,11 +559,11 @@
(def aj a.j)
(when (by aj pivot)
(def ai a.i)
- (:= a.i aj)
- (:= a.j ai)
+ (set a.i aj)
+ (set a.j ai)
(++ i)))
- (:= a.hi a.i)
- (:= a.i pivot)
+ (set a.hi a.i)
+ (set a.i pivot)
i)
(defn sort-help
@@ -567,7 +574,7 @@
(sort-help a (+ piv 1) hi by))
a)
- (fn [a by &]
+ (fn sort [a by &]
(sort-help a 0 (- (length a) 1) (or by order<)))))
(defn sorted
@@ -581,7 +588,7 @@
[f init ind]
(var res init)
(loop [x :in ind]
- (:= res (f res x)))
+ (set res (f res x)))
res)
(defn map
@@ -593,18 +600,18 @@
(var limit (length inds.0))
(loop [i :range [0 ninds]]
(def l (length inds.i))
- (if (< l limit) (:= limit l)))
+ (if (< l limit) (set limit l)))
(def [i1 i2 i3 i4] inds)
(def res (array/new limit))
(case ninds
- 1 (loop [i :range [0 limit]] (:= res.i (f i1.i)))
- 2 (loop [i :range [0 limit]] (:= res.i (f i1.i i2.i)))
- 3 (loop [i :range [0 limit]] (:= res.i (f i1.i i2.i i3.i)))
- 4 (loop [i :range [0 limit]] (:= res.i (f i1.i i2.i i3.i i4.i)))
+ 1 (loop [i :range [0 limit]] (set res.i (f i1.i)))
+ 2 (loop [i :range [0 limit]] (set res.i (f i1.i i2.i)))
+ 3 (loop [i :range [0 limit]] (set res.i (f i1.i i2.i i3.i)))
+ 4 (loop [i :range [0 limit]] (set res.i (f i1.i i2.i i3.i i4.i)))
(loop [i :range [0 limit]]
(def args (array/new ninds))
- (loop [j :range [0 ninds]] (:= args.j inds.j.i))
- (:= res.i (f ;args))))
+ (loop [j :range [0 ninds]] (set args.j inds.j.i))
+ (set res.i (f ;args))))
res)
(defn mapcat
@@ -677,7 +684,7 @@
(var going true)
(while (if (< i len) going)
(def item ind.i)
- (if (pred item) (:= going false) (++ i)))
+ (if (pred item) (set going false) (++ i)))
(if going nil i))
(defn find
@@ -770,7 +777,7 @@
[ind]
(var res true)
(loop [x :in ind :while res]
- (if x nil (:= res x)))
+ (if x nil (set res x)))
res)
(defn reverse
@@ -795,8 +802,8 @@ value, one key will be ignored."
ret)
(defn zipcoll
- "Creates an table or tuple from two arrays/tuples. If a third argument of
- :struct is given result is struct else is table. Returns a new table."
+ "Creates an table or tuple from two arrays/tuples.
+ Returns a new table."
[keys vals]
(def res @{})
(def lk (length keys))
@@ -811,7 +818,7 @@ value, one key will be ignored."
The key then, is associated to the function's return value"
[coll a-key a-function & args]
(def old-value coll.a-key)
- (:= coll.a-key (a-function old-value ;args)))
+ (set coll.a-key (a-function old-value ;args)))
(defn merge-into
"Merges multiple tables/structs into a table. If a key appears in more than one
@@ -820,7 +827,7 @@ value, one key will be ignored."
[tab & colls]
(loop [c :in colls
key :keys c]
- (:= tab.key c.key))
+ (set tab.key c.key))
tab)
(defn merge
@@ -831,7 +838,7 @@ value, one key will be ignored."
(def container @{})
(loop [c :in colls
key :keys c]
- (:= container.key c.key))
+ (set container.key c.key))
container)
(defn keys
@@ -841,7 +848,7 @@ value, one key will be ignored."
(var k (next x nil))
(while (not= nil k)
(array/push arr k)
- (:= k (next x k)))
+ (set k (next x k)))
arr)
(defn values
@@ -851,7 +858,7 @@ value, one key will be ignored."
(var k (next x nil))
(while (not= nil k)
(array/push arr x.k)
- (:= k (next x k)))
+ (set k (next x k)))
arr)
(defn pairs
@@ -861,7 +868,7 @@ value, one key will be ignored."
(var k (next x nil))
(while (not= nil k)
(array/push arr (tuple k x.k))
- (:= k (next x k)))
+ (set k (next x k)))
arr)
(defn frequencies
@@ -871,7 +878,7 @@ value, one key will be ignored."
(loop
[x :in ind]
(def n freqs.x)
- (:= freqs.x (if n (+ 1 n) 1)))
+ (set freqs.x (if n (+ 1 n) 1)))
freqs)
(defn interleave
@@ -892,7 +899,7 @@ value, one key will be ignored."
[xs]
(def ret @[])
(def seen @{})
- (loop [x :in xs] (if seen.x nil (do (:= seen.x true) (array/push ret x))))
+ (loop [x :in xs] (if seen.x nil (do (set seen.x true) (array/push ret x))))
ret)
(defn flatten-into
@@ -925,7 +932,7 @@ value, one key will be ignored."
[sep ind]
(def len (length ind))
(def ret (array/new (- (* 2 len) 1)))
- (if (> len 0) (:= ret.0 ind.0))
+ (if (> len 0) (set ret.0 ind.0))
(var i 1)
(while (< i len)
(array/push ret sep ind.i)
@@ -977,7 +984,7 @@ value, one key will be ignored."
$dict expr
~(if (dictionary? ,$dict)
,((fn aux []
- (:= key (next pattern key))
+ (set key (next pattern key))
(if (= key nil)
(onmatch)
(match-1 (get pattern key) (tuple get $dict key) aux seen))))
@@ -1035,7 +1042,7 @@ value, one key will be ignored."
(def oldcur current)
(def spacer
(if (<= maxcol (+ current (length word) 1))
- (do (:= current 0) "\n ")
+ (do (set current 0) "\n ")
(do (++ current) " ")))
(+= current (length word))
(if (> oldcur 0)
@@ -1052,7 +1059,7 @@ value, one key will be ignored."
(if (> (length word) 0) (pushword))
(when (= b 10)
(buffer/push-string buf "\n ")
- (:= current 0)))))
+ (set current 0)))))
# Last word
(pushword)
@@ -1066,8 +1073,18 @@ value, one key will be ignored."
(if (not x)
(print "symbol " sym " not found.")
(do
+ (def bind-type
+ (string " "
+ (cond
+ x:ref (string :var " (" (type (get x:ref 0)) ")")
+ x:macro :macro
+ (type x:value))
+ "\n"))
(def d x:doc)
- (print "\n\n" (if d (doc-format d) "no documentation found.") "\n\n"))))
+ (print "\n\n"
+ (if d bind-type "")
+ (if d (doc-format d) "no documentation found.")
+ "\n\n"))))
(defmacro doc
"Shows documentation for the given symbol."
@@ -1089,7 +1106,7 @@ value, one key will be ignored."
(var key (next t nil))
(while (not= nil key)
(put newt (macex1 key) (on-value t.key))
- (:= key (next t key)))
+ (set key (next t key)))
newt)
(defn expand-bindings [x]
@@ -1137,7 +1154,7 @@ value, one key will be ignored."
(tuple t.0 (qq t.1)))
(def specs
- {':= expanddef
+ {'set expanddef
'def expanddef
'do expandall
'fn expandfn
@@ -1167,19 +1184,24 @@ value, one key will be ignored."
x))
ret)
-(defn all [pred xs]
+(defn all
+ "Returns true if all xs are truthy, otherwise the first false or nil value."
+ [pred xs]
(var ret true)
- (loop [x :in xs :while ret] (:= ret (pred x)))
+ (loop [x :in xs :while ret] (set ret (pred x)))
ret)
-(defn some [pred xs]
+(defn some
+ "Returns false if all xs are false or nil, otherwise returns the first true value."
+ [pred xs]
(var ret nil)
- (loop [x :in xs :while (not ret)] (if-let [y (pred x)] (:= ret y)))
+ (loop [x :in xs :while (not ret)] (if-let [y (pred x)] (set ret y)))
ret)
-(defn deep-not= [x y]
+(defn deep-not=
"Like not=, but mutable types (arrays, tables, buffers) are considered
equal if they have identical structure. Much slower than not=."
+ [x y]
(def tx (type x))
(or
(not= tx (type y))
@@ -1191,9 +1213,10 @@ value, one key will be ignored."
:buffer (not= (string x) (string y))
(not= x y))))
-(defn deep= [x y]
+(defn deep=
"Like =, but mutable types (arrays, tables, buffers) are considered
equal if they have identical structure. Much slower than =."
+ [x y]
(not (deep-not= x y)))
(defn macex
@@ -1205,8 +1228,8 @@ value, one key will be ignored."
(while (deep-not= current previous)
(if (> (++ counter) 200)
(error "macro expansion too nested"))
- (:= previous current)
- (:= current (macex1 current)))
+ (set previous current)
+ (set current (macex1 current)))
current)
###
@@ -1216,6 +1239,9 @@ value, one key will be ignored."
###
(defn make-env
+ "Create a new environment table. The new environment
+ will inherit bindings from the parent environment, but new
+ bindings will not pollute the parent environment."
[parent &]
(def parent (if parent parent _env))
(def newenv (table/setproto @{} parent))
@@ -1251,12 +1277,12 @@ value, one key will be ignored."
(if (= (type res) :function)
(res)
(do
- (:= good false)
- (def {:error err :line errl :column errc :fiber errf} res)
+ (set good false)
+ (def {:error err :start start :end end :fiber errf} res)
(onstatus
:compile
- (if (< 0 errl)
- (string err "\n in a form at line " errl ", column " errc)
+ (if (<= 0 start)
+ (string err "\n at (" start ":" end ")")
err)
errf
where))))
@@ -1266,7 +1292,7 @@ value, one key will be ignored."
(if going (onstatus (fiber/status f) res f where))))
(def oldenv *env*)
- (:= *env* env)
+ (set *env* env)
# Run loop
(def buf @"")
@@ -1274,22 +1300,21 @@ value, one key will be ignored."
(buffer/clear buf)
(chunks buf p)
(var pindex 0)
+ (var pstatus nil)
(def len (length buf))
- (if (= len 0) (:= going false))
+ (if (= len 0) (set going false))
(while (> len pindex)
(+= pindex (parser/consume p buf pindex))
- (case (parser/status p)
- :full (eval1 (parser/produce p))
- :error (do
- (def (line col) (parser/where p))
- (onstatus :parse
- (string (parser/error p)
- " on line " line
- ", column " col)
- nil
- where)))))
+ (while (= (set pstatus (parser/status p)) :full)
+ (eval1 (parser/produce p)))
+ (when (= pstatus :error)
+ (onstatus :parse
+ (string (parser/error p)
+ " around byte " (parser/where p))
+ nil
+ where))))
- (:= *env* oldenv)
+ (set *env* oldenv)
env)
@@ -1309,7 +1334,7 @@ value, one key will be ignored."
"\n")
(when f
(loop
- [nf :in (reverse (fiber/lineage f))
+ [nf :in (reverse (debug/lineage f))
:before (file/write stderr " (fiber)\n")
{:function func
:tail tail
@@ -1317,8 +1342,8 @@ value, one key will be ignored."
:c c
:name name
:source source
- :line source-line
- :column source-col} :in (fiber/stack nf)]
+ :source-start start
+ :source-end end} :in (debug/stack nf)]
(file/write stderr " in")
(when c (file/write stderr " cfunction"))
(if name
@@ -1327,14 +1352,15 @@ value, one key will be ignored."
(if source
(do
(file/write stderr " [" source "]")
- (if source-line
+ (if start
(file/write
stderr
- " on line "
- (string source-line)
- ", column "
- (string source-col)))))
- (if (and (not source-line) pc)
+ " at ("
+ (string start)
+ ":"
+ (string end)
+ ")"))))
+ (if (and (not start) pc)
(file/write stderr " (pc=" (string pc) ")"))
(when tail (file/write stderr " (tailcall)"))
(file/write stderr "\n"))))
@@ -1346,7 +1372,7 @@ value, one key will be ignored."
(var state (string str))
(defn chunks [buf _]
(def ret state)
- (:= state nil)
+ (set state nil)
(when ret
(buffer/push-string buf str)
(buffer/push-string buf "\n")))
@@ -1354,7 +1380,7 @@ value, one key will be ignored."
(run-context *env* chunks
(fn [sig x f source]
(if (= sig :dead)
- (:= returnval x)
+ (set returnval x)
(status-pp sig x f source)))
"eval")
returnval)
@@ -1410,7 +1436,8 @@ value, one key will be ignored."
path))
(def require
- "Require a module with the given name. Will search all of the paths in
+ "(require module)\n\n
+ Require a module with the given name. Will search all of the paths in
module/paths, then the path as a raw file path. Returns the new environment
returned from compiling and running the file."
(do
@@ -1446,8 +1473,8 @@ value, one key will be ignored."
check
(do
(def newenv (make-env))
- (:= cache.path newenv)
- (:= loading.path true)
+ (set cache.path newenv)
+ (set loading.path true)
(def f (find-mod path))
(if f
(do
@@ -1466,10 +1493,13 @@ value, one key will be ignored."
(if (not n)
(error (string "could not open file for module " path)))
((native n) newenv)))
- (:= loading.path false)
+ (set loading.path false)
newenv)))))
(defn import*
+ "Import a module into a given environment table. This is the
+ functional form of (import ...) that expects and explicit environment
+ table."
[env path & args]
(def targs (table ;args))
(def {:as as
@@ -1483,7 +1513,7 @@ value, one key will be ignored."
(when (not v:private)
(def newv (table/setproto @{:private true} v))
(put env (symbol prefix k) newv))
- (:= k (next newenv k))))
+ (set k (next newenv k))))
(defmacro import
"Import a module. First requires the module, and then merges its
@@ -1507,6 +1537,7 @@ value, one key will be ignored."
(def newenv (make-env))
(default chunks (fn [buf _] (file/read stdin :line buf)))
(default onsignal (fn [sig x f source]
+ (put newenv '_fiber @{:value f})
(case sig
:dead (do
(put newenv '_ @{:value x})
@@ -1519,9 +1550,9 @@ value, one key will be ignored."
[env &]
(default env *env*)
(def envs @[])
- (do (var e env) (while e (array/push envs e) (:= e (table/getproto e))))
+ (do (var e env) (while e (array/push envs e) (set e (table/getproto e))))
(def symbol-set @{})
(loop [envi :in envs
k :keys envi]
- (:= symbol-set.k true))
+ (set symbol-set.k true))
(sort (keys symbol-set)))
diff --git a/src/core/corelib.c b/src/core/corelib.c
index 0190e698..72e80c12 100644
--- a/src/core/corelib.c
+++ b/src/core/corelib.c
@@ -324,7 +324,7 @@ static const JanetReg cfuns[] = {
"(buffer & xs)\n\n"
"Creates a new buffer by concatenating values together. Values are "
"converted to bytes via describe if they are not byte sequences. Returns "
- "the new symbol."
+ "the new buffer."
},
{"abstract?", janet_core_is_abstract,
"(abstract? x)\n\n"
@@ -384,7 +384,7 @@ static const JanetReg cfuns[] = {
{"gcsetinterval", janet_core_gcsetinterval,
"(gcsetinterval interval)\n\n"
"Set an integer number of bytes to allocate before running garbage collection. "
- "Low values interval will be slower but use less memory. "
+ "Low valuesi for interval will be slower but use less memory. "
"High values will be faster but use more memory."
},
{"gcinterval", janet_core_gcinterval,
@@ -406,9 +406,9 @@ static const JanetReg cfuns[] = {
"\t:string\n"
"\t:buffer\n"
"\t:symbol\n"
- "\t:abstract\n"
"\t:function\n"
- "\t:cfunction"
+ "\t:cfunction\n\n"
+ "or another symbol for an abstract type."
},
{"next", janet_core_next,
"(next dict key)\n\n"
@@ -711,25 +711,25 @@ JanetTable *janet_core_env(void) {
"Returns the quotient of xs. If xs is empty, returns 1. If xs has one value x, returns "
"the reciprocal of x. Otherwise return the first value of xs repeatedly divided by the remaining "
"values. Division by two integers uses truncating division.");
- templatize_varop(env, JANET_FUN_BAND, "&", -1, -1, JOP_BAND,
- "(& & xs)\n\n"
+ templatize_varop(env, JANET_FUN_BAND, "band", -1, -1, JOP_BAND,
+ "(band & xs)\n\n"
"Returns the bitwise and of all values in xs. Each x in xs must be an integer.");
- templatize_varop(env, JANET_FUN_BOR, "|", 0, 0, JOP_BOR,
- "(| & xs)\n\n"
+ templatize_varop(env, JANET_FUN_BOR, "bor", 0, 0, JOP_BOR,
+ "(bor & xs)\n\n"
"Returns the bitwise or of all values in xs. Each x in xs must be an integer.");
- templatize_varop(env, JANET_FUN_BXOR, "^", 0, 0, JOP_BXOR,
- "(^ & xs)\n\n"
+ templatize_varop(env, JANET_FUN_BXOR, "bxor", 0, 0, JOP_BXOR,
+ "(bxor & xs)\n\n"
"Returns the bitwise xor of all values in xs. Each in xs must be an integer.");
- templatize_varop(env, JANET_FUN_LSHIFT, "<<", 1, 1, JOP_SHIFT_LEFT,
- "(<< x & shifts)\n\n"
+ templatize_varop(env, JANET_FUN_LSHIFT, "blshift", 1, 1, JOP_SHIFT_LEFT,
+ "(blshift x & shifts)\n\n"
"Returns the value of x bit shifted left by the sum of all values in shifts. x "
"and each element in shift must be an integer.");
- templatize_varop(env, JANET_FUN_RSHIFT, ">>", 1, 1, JOP_SHIFT_RIGHT,
- "(>> x & shifts)\n\n"
+ templatize_varop(env, JANET_FUN_RSHIFT, "brshift", 1, 1, JOP_SHIFT_RIGHT,
+ "(brshift x & shifts)\n\n"
"Returns the value of x bit shifted right by the sum of all values in shifts. x "
"and each element in shift must be an integer.");
- templatize_varop(env, JANET_FUN_RSHIFTU, ">>>", 1, 1, JOP_SHIFT_RIGHT_UNSIGNED,
- "(>> x & shifts)\n\n"
+ templatize_varop(env, JANET_FUN_RSHIFTU, "brushift", 1, 1, JOP_SHIFT_RIGHT_UNSIGNED,
+ "(brushift x & shifts)\n\n"
"Returns the value of x bit shifted right by the sum of all values in shifts. x "
"and each element in shift must be an integer. The sign of x is not preserved, so "
"for positive shifts the return value will always be positive.");
@@ -801,6 +801,7 @@ JanetTable *janet_core_env(void) {
janet_lib_os(args);
janet_lib_parse(args);
janet_lib_compile(args);
+ janet_lib_debug(args);
janet_lib_string(args);
janet_lib_marsh(args);
#ifdef JANET_ASSEMBLER
diff --git a/src/core/debug.c b/src/core/debug.c
new file mode 100644
index 00000000..5e387024
--- /dev/null
+++ b/src/core/debug.c
@@ -0,0 +1,313 @@
+/*
+* Copyright (c) 2018 Calvin Rose
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#include
+#include "gc.h"
+#include "state.h"
+
+/* Implements functionality to build a debugger from within janet.
+ * The repl should also be able to serve as pretty featured debugger
+ * out of the box. */
+
+/* Add a break point to a function */
+int janet_debug_break(JanetFuncDef *def, int32_t pc) {
+ if (pc >= def->bytecode_length || pc < 0)
+ return 1;
+ def->bytecode[pc] |= 0x80;
+ return 0;
+}
+
+/* Remove a break point from a function */
+int janet_debug_unbreak(JanetFuncDef *def, int32_t pc) {
+ if (pc >= def->bytecode_length || pc < 0)
+ return 1;
+ def->bytecode[pc] &= ~((uint32_t)0x80);
+ return 0;
+}
+
+/*
+ * Find a location for a breakpoint given a source file an
+ * location.
+ */
+int janet_debug_find(
+ JanetFuncDef **def_out, int32_t *pc_out,
+ const uint8_t *source, int32_t offset) {
+ /* Scan the heap for right func def */
+ JanetGCMemoryHeader *current = janet_vm_blocks;
+ /* Keep track of the best source mapping we have seen so far */
+ int32_t besti = -1;
+ int32_t best_range = INT32_MAX;
+ JanetFuncDef *best_def = NULL;
+ while (NULL != current) {
+ if ((current->flags & JANET_MEM_TYPEBITS) == JANET_MEMORY_FUNCDEF) {
+ JanetFuncDef *def = (JanetFuncDef *)(current + 1);
+ if (def->sourcemap &&
+ def->source &&
+ !janet_string_compare(source, def->source)) {
+ /* Correct source file, check mappings. The chosen
+ * pc index is the first match with the smallest range. */
+ int32_t i;
+ for (i = 0; i < def->bytecode_length; i++) {
+ int32_t start = def->sourcemap[i].start;
+ int32_t end = def->sourcemap[i].end;
+ if (end - start < best_range &&
+ start <= offset &&
+ end >= offset) {
+ best_range = end - start;
+ besti = i;
+ best_def = def;
+ }
+ }
+ }
+ }
+ current = current->next;
+ }
+ if (best_def) {
+ *def_out = best_def;
+ *pc_out = besti;
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+/*
+ * CFuns
+ */
+
+/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
+ * Takes a source file name and byte offset. */
+static int helper_find(JanetArgs args, JanetFuncDef **def, int32_t *bytecode_offset) {
+ const uint8_t *source;
+ int32_t source_offset;
+ JANET_FIXARITY(args, 2);
+ JANET_ARG_STRING(source, args, 0);
+ JANET_ARG_INTEGER(source_offset, args, 1);
+ if (janet_debug_find(
+ def, bytecode_offset, source, source_offset)) {
+ JANET_THROW(args, "could not find breakpoint");
+ }
+ JANET_RETURN_NIL(args);
+}
+
+/* Helper to find funcdef and bytecode offset to insert or remove breakpoints.
+ * Takes a function and byte offset*/
+static int helper_find_fun(JanetArgs args, JanetFuncDef **def, int32_t *bytecode_offset) {
+ JanetFunction *func;
+ int32_t offset = 0;
+ JANET_MINARITY(args, 1);
+ JANET_MAXARITY(args, 2);
+ JANET_ARG_FUNCTION(func, args, 0);
+ if (args.n == 2) {
+ JANET_ARG_INTEGER(offset, args, 1);
+ }
+ *def = func->def;
+ *bytecode_offset = offset;
+ JANET_RETURN_NIL(args);
+}
+
+static int cfun_break(JanetArgs args) {
+ JanetFuncDef *def;
+ int32_t offset;
+ int status = helper_find(args, &def, &offset);
+ if (status == 0) janet_debug_break(def, offset);
+ return status;
+}
+
+static int cfun_unbreak(JanetArgs args) {
+ JanetFuncDef *def;
+ int32_t offset;
+ int status = helper_find(args, &def, &offset);
+ if (status == 0) janet_debug_unbreak(def, offset);
+ return status;
+}
+
+static int cfun_fbreak(JanetArgs args) {
+ JanetFuncDef *def;
+ int32_t offset;
+ int status = helper_find_fun(args, &def, &offset);
+ if (status == 0) {
+ if (janet_debug_break(def, offset)) {
+ JANET_THROW(args, "could not find breakpoint");
+ }
+ }
+ return status;
+}
+
+static int cfun_unfbreak(JanetArgs args) {
+ JanetFuncDef *def;
+ int32_t offset;
+ int status = helper_find_fun(args, &def, &offset);
+ if (status == 0) {
+ if (janet_debug_unbreak(def, offset)) {
+ JANET_THROW(args, "could not find breakpoint");
+ }
+ }
+ return status;
+}
+
+static int cfun_lineage(JanetArgs args) {
+ JanetFiber *fiber;
+ JanetArray *array;
+ JANET_FIXARITY(args, 1);
+ JANET_ARG_FIBER(fiber, args, 0);
+ array = janet_array(0);
+ while (fiber) {
+ janet_array_push(array, janet_wrap_fiber(fiber));
+ fiber = fiber->child;
+ }
+ JANET_RETURN_ARRAY(args, array);
+}
+
+/* Extract info from one stack frame */
+static Janet doframe(JanetStackFrame *frame) {
+ int32_t off;
+ JanetTable *t = janet_table(3);
+ JanetFuncDef *def = NULL;
+ if (frame->func) {
+ janet_table_put(t, janet_csymbolv(":function"), janet_wrap_function(frame->func));
+ def = frame->func->def;
+ if (def->name) {
+ janet_table_put(t, janet_csymbolv(":name"), janet_wrap_string(def->name));
+ }
+ } else {
+ JanetCFunction cfun = (JanetCFunction)(frame->pc);
+ if (cfun) {
+ Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
+ if (!janet_checktype(name, JANET_NIL)) {
+ janet_table_put(t, janet_csymbolv(":name"), name);
+ }
+ }
+ janet_table_put(t, janet_csymbolv(":c"), janet_wrap_true());
+ }
+ if (frame->flags & JANET_STACKFRAME_TAILCALL) {
+ janet_table_put(t, janet_csymbolv(":tail"), janet_wrap_true());
+ }
+ if (frame->func && frame->pc) {
+ Janet *stack = (Janet *)frame + JANET_FRAME_SIZE;
+ JanetArray *slots;
+ off = (int32_t) (frame->pc - def->bytecode);
+ janet_table_put(t, janet_csymbolv(":pc"), janet_wrap_integer(off));
+ if (def->sourcemap) {
+ JanetSourceMapping mapping = def->sourcemap[off];
+ janet_table_put(t, janet_csymbolv(":source-start"), janet_wrap_integer(mapping.start));
+ janet_table_put(t, janet_csymbolv(":source-end"), janet_wrap_integer(mapping.end));
+ }
+ if (def->source) {
+ janet_table_put(t, janet_csymbolv(":source"), janet_wrap_string(def->source));
+ }
+ /* Add stack arguments */
+ slots = janet_array(def->slotcount);
+ memcpy(slots->data, stack, sizeof(Janet) * def->slotcount);
+ slots->count = def->slotcount;
+ janet_table_put(t, janet_csymbolv(":slots"), janet_wrap_array(slots));
+ }
+ return janet_wrap_table(t);
+}
+
+static int cfun_stack(JanetArgs args) {
+ JanetFiber *fiber;
+ JanetArray *array;
+ JANET_FIXARITY(args, 1);
+ JANET_ARG_FIBER(fiber, args, 0);
+ array = janet_array(0);
+ {
+ int32_t i = fiber->frame;
+ JanetStackFrame *frame;
+ while (i > 0) {
+ frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
+ janet_array_push(array, doframe(frame));
+ i = frame->prevframe;
+ }
+ }
+ JANET_RETURN_ARRAY(args, array);
+}
+
+static int cfun_argstack(JanetArgs args) {
+ JanetFiber *fiber;
+ JanetArray *array;
+ JANET_FIXARITY(args, 1);
+ JANET_ARG_FIBER(fiber, args, 0);
+ array = janet_array(fiber->stacktop - fiber->stackstart);
+ memcpy(array->data, fiber->data + fiber->stackstart, array->capacity * sizeof(Janet));
+ array->count = array->capacity;
+ JANET_RETURN_ARRAY(args, array);
+}
+
+static const JanetReg cfuns[] = {
+ {"debug/break", cfun_break,
+ "(debug/break source byte-offset)\n\n"
+ "Sets a breakpoint with source a key at a given byte offset. An offset "
+ "of 0 is the first byte in a file. Will throw an error if the breakpoint location "
+ "cannot be found. For example\n\n"
+ "\t(debug/break \"core.janet\" 1000)\n\n"
+ "wil set a breakpoint at the 1000th byte of the file core.janet."},
+ {"debug/unbreak", cfun_unbreak,
+ "(debug/unbreak source byte-offset)\n\n"
+ "Remove a breakpoint with a source key at a given byte offset. An offset "
+ "of 0 is the first byte in a file. Will throw an error if the breakpoint "
+ "cannot be found."},
+ {"debug/fbreak", cfun_fbreak,
+ "(debug/fbreak fun [,pc=0])\n\n"
+ "Set a breakpoint in a given function. pc is an optional offset, which "
+ "is in bytecode instructions. fun is a function value. Will throw an error "
+ "if the offset is too large or negative."},
+ {"debug/unfbreak", cfun_unfbreak,
+ "(debug/unfbreak fun [,pc=0])\n\n"
+ "Unset a breakpoint set with debug/fbreak."},
+ {"debug/arg-stack", cfun_argstack,
+ "(debug/arg-stack fiber)\n\n"
+ "Gets all values currently on the fiber's argument stack. Normally, "
+ "this should be empty unless the fiber signals while pushing arguments "
+ "to make a function call. Returns a new array."},
+ {"debug/stack", cfun_stack,
+ "(debug/stack fib)\n\n"
+ "Gets information about the stack as an array of tables. Each table "
+ "in the array contains information about a stack frame. The top most, current "
+ "stack frame is the first table in the array, and the bottom most stack frame "
+ "is the last value. Each stack frame contains some of the following attributes:\n\n"
+ "\t:c - true if the stack frame is a c function invocation\n"
+ "\t:column - the current source column of the stack frame\n"
+ "\t:function - the function that the stack frame represents\n"
+ "\t:line - the current source line of the stack frame\n"
+ "\t:name - the human friendly name of the function\n"
+ "\t:pc - integer indicating the location of the program counter\n"
+ "\t:source - string with filename or other identifier for the source code\n"
+ "\t:slots - array of all values in each slot\n"
+ "\t:tail - boolean indicating a tail call"
+ },
+ {"debug/lineage", cfun_lineage,
+ "(debug/lineage fib)\n\n"
+ "Returns an array of all child fibers from a root fiber. This function "
+ "is useful when a fiber signals or errors to an ancestor fiber. Using this function, "
+ "the fiber handling the error can see which fiber raised the signal. This function should "
+ "be used mostly for debugging purposes."
+ },
+ {NULL, NULL, NULL}
+};
+
+/* Module entry point */
+int janet_lib_debug(JanetArgs args) {
+ JanetTable *env = janet_env(args);
+ janet_cfuns(env, NULL, cfuns);
+ return 0;
+}
diff --git a/src/core/fiber.c b/src/core/fiber.c
index 7f806c0c..31f9b6e3 100644
--- a/src/core/fiber.c
+++ b/src/core/fiber.c
@@ -349,88 +349,11 @@ static int cfun_new(JanetArgs args) {
static int cfun_status(JanetArgs args) {
JanetFiber *fiber;
- const char *status = "";
JANET_FIXARITY(args, 1);
JANET_ARG_FIBER(fiber, args, 0);
uint32_t s = (fiber->flags & JANET_FIBER_STATUS_MASK) >>
JANET_FIBER_STATUS_OFFSET;
- switch (s) {
- case JANET_STATUS_DEAD: status = ":dead"; break;
- case JANET_STATUS_ERROR: status = ":error"; break;
- case JANET_STATUS_DEBUG: status = ":debug"; break;
- case JANET_STATUS_PENDING: status = ":pending"; break;
- case JANET_STATUS_USER0: status = ":user0"; break;
- case JANET_STATUS_USER1: status = ":user1"; break;
- case JANET_STATUS_USER2: status = ":user2"; break;
- case JANET_STATUS_USER3: status = ":user3"; break;
- case JANET_STATUS_USER4: status = ":user4"; break;
- case JANET_STATUS_USER5: status = ":user5"; break;
- case JANET_STATUS_USER6: status = ":user6"; break;
- case JANET_STATUS_USER7: status = ":user7"; break;
- case JANET_STATUS_USER8: status = ":user8"; break;
- case JANET_STATUS_USER9: status = ":user9"; break;
- case JANET_STATUS_NEW: status = ":new"; break;
- default:
- case JANET_STATUS_ALIVE: status = ":alive"; break;
- }
- JANET_RETURN_CSYMBOL(args, status);
-}
-
-/* Extract info from one stack frame */
-static Janet doframe(JanetStackFrame *frame) {
- int32_t off;
- JanetTable *t = janet_table(3);
- JanetFuncDef *def = NULL;
- if (frame->func) {
- janet_table_put(t, janet_csymbolv(":function"), janet_wrap_function(frame->func));
- def = frame->func->def;
- if (def->name) {
- janet_table_put(t, janet_csymbolv(":name"), janet_wrap_string(def->name));
- }
- } else {
- JanetCFunction cfun = (JanetCFunction)(frame->pc);
- if (cfun) {
- Janet name = janet_table_get(janet_vm_registry, janet_wrap_cfunction(cfun));
- if (!janet_checktype(name, JANET_NIL)) {
- janet_table_put(t, janet_csymbolv(":name"), name);
- }
- }
- janet_table_put(t, janet_csymbolv(":c"), janet_wrap_true());
- }
- if (frame->flags & JANET_STACKFRAME_TAILCALL) {
- janet_table_put(t, janet_csymbolv(":tail"), janet_wrap_true());
- }
- if (frame->func && frame->pc) {
- off = (int32_t) (frame->pc - def->bytecode);
- janet_table_put(t, janet_csymbolv(":pc"), janet_wrap_integer(off));
- if (def->sourcemap) {
- JanetSourceMapping mapping = def->sourcemap[off];
- janet_table_put(t, janet_csymbolv(":line"), janet_wrap_integer(mapping.line));
- janet_table_put(t, janet_csymbolv(":column"), janet_wrap_integer(mapping.column));
- }
- if (def->source) {
- janet_table_put(t, janet_csymbolv(":source"), janet_wrap_string(def->source));
- }
- }
- return janet_wrap_table(t);
-}
-
-static int cfun_stack(JanetArgs args) {
- JanetFiber *fiber;
- JanetArray *array;
- JANET_FIXARITY(args, 1);
- JANET_ARG_FIBER(fiber, args, 0);
- array = janet_array(0);
- {
- int32_t i = fiber->frame;
- JanetStackFrame *frame;
- while (i > 0) {
- frame = (JanetStackFrame *)(fiber->data + i - JANET_FRAME_SIZE);
- janet_array_push(array, doframe(frame));
- i = frame->prevframe;
- }
- }
- JANET_RETURN_ARRAY(args, array);
+ JANET_RETURN_CSYMBOL(args, janet_status_names[s]);
}
static int cfun_current(JanetArgs args) {
@@ -438,19 +361,6 @@ static int cfun_current(JanetArgs args) {
JANET_RETURN_FIBER(args, janet_vm_fiber);
}
-static int cfun_lineage(JanetArgs args) {
- JanetFiber *fiber;
- JanetArray *array;
- JANET_FIXARITY(args, 1);
- JANET_ARG_FIBER(fiber, args, 0);
- array = janet_array(0);
- while (fiber) {
- janet_array_push(array, janet_wrap_fiber(fiber));
- fiber = fiber->child;
- }
- JANET_RETURN_ARRAY(args, array);
-}
-
static int cfun_maxstack(JanetArgs args) {
JanetFiber *fiber;
JANET_FIXARITY(args, 1);
@@ -500,32 +410,10 @@ static const JanetReg cfuns[] = {
"\t:alive - the fiber is currently running and cannot be resumed\n"
"\t:new - the fiber has just been created and not yet run"
},
- {"fiber/stack", cfun_stack,
- "(fiber/stack fib)\n\n"
- "Gets information about the stack as an array of tables. Each table "
- "in the array contains information about a stack frame. The top most, current "
- "stack frame is the first table in the array, and the bottom most stack frame "
- "is the last value. Each stack frame contains some of the following attributes:\n\n"
- "\t:c - true if the stack frame is a c function invokation\n"
- "\t:column - the current source column of the stack frame\n"
- "\t:function - the function that the stack frame represents\n"
- "\t:line - the current source line of the stack frame\n"
- "\t:name - the human friendly name of the function\n"
- "\t:pc - integer indicating the location of the program counter\n"
- "\t:source - string with filename or other identifier for the source code\n"
- "\t:tail - boolean indicating a tail call"
- },
{"fiber/current", cfun_current,
"(fiber/current)\n\n"
"Returns the currently running fiber."
},
- {"fiber/lineage", cfun_lineage,
- "(fiber/lineage fib)\n\n"
- "Returns an array of all child fibers from a root fiber. This function "
- "is useful when a fiber signals or errors to an ancestor fiber. Using this function, "
- "the fiber handling the error can see which fiber raised the signal. This function should "
- "be used mostly for debugging purposes."
- },
{"fiber/maxstack", cfun_maxstack,
"(fiber/maxstack fib)\n\n"
"Gets the maximum stack size in janet values allowed for a fiber. While memory for "
diff --git a/src/core/io.c b/src/core/io.c
index 7fc4edca..7d23e1ba 100644
--- a/src/core/io.c
+++ b/src/core/io.c
@@ -47,7 +47,7 @@ struct IOFile {
static int janet_io_gc(void *p, size_t len);
JanetAbstractType janet_io_filetype = {
- ":core.file",
+ ":core/file",
janet_io_gc,
NULL
};
diff --git a/src/core/marsh.c b/src/core/marsh.c
index 4b794e92..53c9103a 100644
--- a/src/core/marsh.c
+++ b/src/core/marsh.c
@@ -234,8 +234,8 @@ static void marshal_one_def(MarshalState *st, JanetFuncDef *def, int flags) {
if (def->flags & JANET_FUNCDEF_FLAG_HASSOURCEMAP) {
for (int32_t i = 0; i < def->bytecode_length; i++) {
JanetSourceMapping map = def->sourcemap[i];
- pushint(st, map.line);
- pushint(st, map.column);
+ pushint(st, map.start);
+ pushint(st, map.end);
}
}
}
@@ -740,8 +740,8 @@ static const uint8_t *unmarshal_one_def(
JANET_OUT_OF_MEMORY;
}
for (int32_t i = 0; i < bytecode_length; i++) {
- def->sourcemap[i].line = readint(st, &data);
- def->sourcemap[i].column = readint(st, &data);
+ def->sourcemap[i].start = readint(st, &data);
+ def->sourcemap[i].end = readint(st, &data);
}
} else {
def->sourcemap = NULL;
diff --git a/src/core/parse.c b/src/core/parse.c
index a4845c06..3f76191d 100644
--- a/src/core/parse.c
+++ b/src/core/parse.c
@@ -102,8 +102,7 @@ struct JanetParseState {
int32_t counter;
int32_t argn;
int flags;
- size_t start_line;
- size_t start_col;
+ size_t start;
Consumer consumer;
};
@@ -147,8 +146,7 @@ static void pushstate(JanetParser *p, Consumer consumer, int flags) {
s.argn = 0;
s.flags = flags;
s.consumer = consumer;
- s.start_line = p->line;
- s.start_col = p->col;
+ s.start = p->offset;
_pushstate(p, s);
}
@@ -159,8 +157,8 @@ static void popstate(JanetParser *p, Janet val) {
if (newtop->flags & PFLAG_CONTAINER) {
/* Source mapping info */
if (janet_checktype(val, JANET_TUPLE)) {
- janet_tuple_sm_line(janet_unwrap_tuple(val)) = (int32_t) top.start_line;
- janet_tuple_sm_col(janet_unwrap_tuple(val)) = (int32_t) top.start_col;
+ janet_tuple_sm_start(janet_unwrap_tuple(val)) = (int32_t) top.start;
+ janet_tuple_sm_end(janet_unwrap_tuple(val)) = (int32_t) p->offset;
}
newtop->argn++;
push_arg(p, val);
@@ -176,8 +174,8 @@ static void popstate(JanetParser *p, Janet val) {
t[0] = janet_csymbolv(which);
t[1] = val;
/* Quote source mapping info */
- janet_tuple_sm_line(t) = (int32_t) newtop->start_line;
- janet_tuple_sm_col(t) = (int32_t) newtop->start_col;
+ janet_tuple_sm_start(t) = (int32_t) newtop->start;
+ janet_tuple_sm_end(t) = (int32_t) p->offset;
val = janet_wrap_tuple(janet_tuple_end(t));
} else {
return;
@@ -522,12 +520,7 @@ static int root(JanetParser *p, JanetParseState *state, uint8_t c) {
int janet_parser_consume(JanetParser *parser, uint8_t c) {
int consumed = 0;
if (parser->error) return 0;
- if (c == '\n') {
- parser->line++;
- parser->col = 0;
- } else if (c != '\r') {
- parser->col++;
- }
+ parser->offset++;
while (!consumed && !parser->error) {
JanetParseState *state = parser->states + parser->statecount - 1;
consumed = state->consumer(parser, state, c);
@@ -584,9 +577,8 @@ void janet_parser_init(JanetParser *parser) {
parser->statecount = 0;
parser->statecap = 0;
parser->error = NULL;
- parser->line = 1;
- parser->col = 0;
parser->lookback = -1;
+ parser->offset = 0;
pushstate(parser, root, PFLAG_CONTAINER);
}
@@ -617,7 +609,7 @@ static int parsergc(void *p, size_t size) {
}
static JanetAbstractType janet_parse_parsertype = {
- ":core.parser",
+ ":core/parser",
parsergc,
parsermark
};
@@ -742,10 +734,7 @@ static int cfun_where(JanetArgs args) {
JANET_FIXARITY(args, 1);
JANET_CHECKABSTRACT(args, 0, &janet_parse_parsertype);
p = (JanetParser *) janet_unwrap_abstract(args.v[0]);
- Janet *tup = janet_tuple_begin(2);
- tup[0] = janet_wrap_integer((int32_t)p->line);
- tup[1] = janet_wrap_integer((int32_t)p->col);
- JANET_RETURN_TUPLE(args, janet_tuple_end(tup));
+ JANET_RETURN_INTEGER(args, p->offset);
}
static int cfun_state(JanetArgs args) {
diff --git a/src/core/run.c b/src/core/run.c
index 1d5be862..6a44ab65 100644
--- a/src/core/run.c
+++ b/src/core/run.c
@@ -67,7 +67,7 @@ void janet_stacktrace(JanetFiber *fiber, const char *errtype, Janet err) {
int32_t off = (int32_t) (frame->pc - def->bytecode);
if (def->sourcemap) {
JanetSourceMapping mapping = def->sourcemap[off];
- fprintf(stderr, " on line %d, column %d", mapping.line, mapping.column);
+ fprintf(stderr, " at (%d:%d)", mapping.start, mapping.end);
} else {
fprintf(stderr, " pc=%d", off);
}
@@ -75,6 +75,8 @@ void janet_stacktrace(JanetFiber *fiber, const char *errtype, Janet err) {
fprintf(stderr, "\n");
}
}
+
+ janet_v_free(fibers);
}
/* Run a string */
diff --git a/src/core/specials.c b/src/core/specials.c
index ab7b56ad..de118889 100644
--- a/src/core/specials.c
+++ b/src/core/specials.c
@@ -172,6 +172,15 @@ static int destructure(JanetCompiler *c,
}
}
+/* Create a source map for definitions. */
+static const Janet *janetc_make_sourcemap(JanetCompiler *c) {
+ Janet *tup = janet_tuple_begin(3);
+ tup[0] = janet_wrap_string(c->source);
+ tup[1] = janet_wrap_integer(c->current_mapping.start);
+ tup[2] = janet_wrap_integer(c->current_mapping.end);
+ return janet_tuple_end(tup);
+}
+
static JanetSlot janetc_varset(JanetFopts opts, int32_t argn, const Janet *argv) {
/*JanetFopts subopts = janetc_fopts_default(opts.compiler);*/
/*JanetSlot ret, dest;*/
@@ -252,6 +261,8 @@ static int varleaf(
JanetArray *ref = janet_array(1);
janet_array_push(ref, janet_wrap_nil());
janet_table_put(reftab, janet_csymbolv(":ref"), janet_wrap_array(ref));
+ janet_table_put(reftab, janet_csymbolv(":source-map"),
+ janet_wrap_tuple(janetc_make_sourcemap(c)));
janet_table_put(c->env, janet_wrap_symbol(sym), janet_wrap_table(reftab));
refslot = janetc_cslot(janet_wrap_array(ref));
janetc_emit_ssu(c, JOP_PUT_INDEX, refslot, s, 0, 0);
@@ -278,6 +289,8 @@ static int defleaf(
JanetTable *attr) {
if (c->scope->flags & JANET_SCOPE_TOP) {
JanetTable *tab = janet_table(2);
+ janet_table_put(tab, janet_csymbolv(":source-map"),
+ janet_wrap_tuple(janetc_make_sourcemap(c)));
tab->proto = attr;
JanetSlot valsym = janetc_cslot(janet_csymbolv(":value"));
JanetSlot tabslot = janetc_cslot(janet_wrap_table(tab));
@@ -648,16 +661,15 @@ error2:
/* Keep in lexicographic order */
static const JanetSpecial janetc_specials[] = {
- {":=", janetc_varset},
{"def", janetc_def},
{"do", janetc_do},
{"fn", janetc_fn},
{"if", janetc_if},
{"quasiquote", janetc_quasiquote},
{"quote", janetc_quote},
+ {"set", janetc_varset},
{"splice", janetc_splice},
{"unquote", janetc_unquote},
- {"unquote", janetc_unquote},
{"var", janetc_var},
{"while", janetc_while}
};
diff --git a/src/core/tuple.c b/src/core/tuple.c
index c8f3dd65..b64a9b52 100644
--- a/src/core/tuple.c
+++ b/src/core/tuple.c
@@ -32,8 +32,8 @@ Janet *janet_tuple_begin(int32_t length) {
char *data = janet_gcalloc(JANET_MEMORY_TUPLE, 4 * sizeof(int32_t) + length * sizeof(Janet));
Janet *tuple = (Janet *)(data + (4 * sizeof(int32_t)));
janet_tuple_length(tuple) = length;
- janet_tuple_sm_line(tuple) = 0;
- janet_tuple_sm_col(tuple) = 0;
+ janet_tuple_sm_start(tuple) = -1;
+ janet_tuple_sm_end(tuple) = -1;
return tuple;
}
diff --git a/src/core/util.c b/src/core/util.c
index 27450911..200e381f 100644
--- a/src/core/util.c
+++ b/src/core/util.c
@@ -53,6 +53,42 @@ const char *const janet_type_names[16] = {
":abstract"
};
+const char *const janet_signal_names[14] = {
+ ":ok",
+ ":error",
+ ":debug",
+ ":yield",
+ ":user0",
+ ":user1",
+ ":user2",
+ ":user3",
+ ":user4",
+ ":user5",
+ ":user6",
+ ":user7",
+ ":user8",
+ ":user9"
+};
+
+const char *const janet_status_names[16] = {
+ ":dead",
+ ":error",
+ ":debug",
+ ":pending",
+ ":user0",
+ ":user1",
+ ":user2",
+ ":user3",
+ ":user4",
+ ":user5",
+ ":user6",
+ ":user7",
+ ":user8",
+ ":user9",
+ ":new",
+ ":alive"
+};
+
/* Calculate hash for string */
int32_t janet_string_calchash(const uint8_t *str, int32_t len) {
diff --git a/src/core/util.h b/src/core/util.h
index 4b1cecfb..1bc7cc4d 100644
--- a/src/core/util.h
+++ b/src/core/util.h
@@ -57,5 +57,6 @@ int janet_lib_parse(JanetArgs args);
int janet_lib_asm(JanetArgs args);
#endif
int janet_lib_compile(JanetArgs args);
+int janet_lib_debug(JanetArgs args);
#endif
diff --git a/src/core/vm.c b/src/core/vm.c
index 09a1b6f3..1e1d2453 100644
--- a/src/core/vm.c
+++ b/src/core/vm.c
@@ -54,6 +54,8 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
/* Expected types on type error */
uint16_t expected_types;
+ uint8_t first_opcode;
+
/* Signal to return when done */
JanetSignal signal = JANET_SIGNAL_OK;
@@ -92,16 +94,24 @@ JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out) {
* instruction. */
retreg = in;
goto vm_resume_child;
- } else if (startstatus != JANET_STATUS_NEW) {
+ } else if (startstatus != JANET_STATUS_NEW &&
+ ((*pc & 0xFF) == JOP_SIGNAL)) {
/* Only should be hit if child is waiting on a SIGNAL instruction */
/* If waiting for response to signal, use input and increment pc */
stack[oparg(1, 0xFF)] = in;
pc++;
}
+ /* The first opcode to execute. If the first opcode has
+ * the breakpoint bit set and we were in the debug state, skip
+ * that first breakpoint. */
+ first_opcode = (startstatus == JANET_STATUS_DEBUG)
+ ? (*pc & 0x7F)
+ : (*pc & 0xFF);
+
/* Use computed gotos for GCC and clang, otherwise use switch */
-#ifdef __GNUC__
-#define VM_START() {vm_next();
+#ifdef ____GNUC__
+#define VM_START() { goto *op_lookup[first_opcode];
#define VM_END() }
#define VM_OP(op) label_##op :
#define VM_DEFAULT() label_unknown_op:
@@ -193,11 +203,11 @@ static void *op_lookup[255] = {
&&label_unknown_op
};
#else
-#define VM_START() for(;;){switch(*pc & 0xFF){
+#define VM_START() uint8_t opcode = first_opcode; for (;;) {switch(opcode) {
#define VM_END() }}
#define VM_OP(op) case op :
#define VM_DEFAULT() default:
-#define vm_next() continue
+#define vm_next() opcode = *pc & 0xFF; continue
#endif
#define vm_checkgc_next() janet_maybe_collect(); vm_next()
@@ -279,6 +289,7 @@ static void *op_lookup[255] = {
VM_START();
VM_DEFAULT();
+ signal = JANET_SIGNAL_DEBUG;
retreg = janet_wrap_nil();
goto vm_exit;
@@ -535,7 +546,6 @@ static void *op_lookup[255] = {
pc++;
vm_next();
- /* Candidate */
VM_OP(JOP_GREATER_THAN_INTEGER)
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
janet_unwrap_integer(stack[oparg(2, 0xFF)]) >
@@ -543,7 +553,6 @@ static void *op_lookup[255] = {
pc++;
vm_next();
- /* Candidate */
VM_OP(JOP_GREATER_THAN_IMMEDIATE)
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
janet_unwrap_integer(stack[oparg(2, 0xFF)]) > ((*(int32_t *)pc) >> 24)
@@ -551,7 +560,6 @@ static void *op_lookup[255] = {
pc++;
vm_next();
- /* Candidate */
VM_OP(JOP_GREATER_THAN_REAL)
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
janet_unwrap_real(stack[oparg(2, 0xFF)]) >
@@ -559,7 +567,6 @@ static void *op_lookup[255] = {
pc++;
vm_next();
- /* Candidate */
VM_OP(JOP_GREATER_THAN_EQUAL_REAL)
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
janet_unwrap_real(stack[oparg(2, 0xFF)]) >=
@@ -575,7 +582,6 @@ static void *op_lookup[255] = {
pc++;
vm_next();
- /* Candidate */
VM_OP(JOP_EQUALS_INTEGER)
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
janet_unwrap_integer(stack[oparg(2, 0xFF)]) ==
@@ -584,7 +590,6 @@ static void *op_lookup[255] = {
pc++;
vm_next();
- /* Candidate */
VM_OP(JOP_EQUALS_REAL)
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
janet_unwrap_real(stack[oparg(2, 0xFF)]) ==
@@ -593,7 +598,6 @@ static void *op_lookup[255] = {
pc++;
vm_next();
- /* Candidate */
VM_OP(JOP_EQUALS_IMMEDIATE)
stack[oparg(1, 0xFF)] = janet_wrap_boolean(
janet_unwrap_integer(stack[oparg(2, 0xFF)]) == ((*(int32_t *)pc) >> 24)
diff --git a/src/include/janet/janet.h b/src/include/janet/janet.h
index ec5bcf1d..f3a6cddd 100644
--- a/src/include/janet/janet.h
+++ b/src/include/janet/janet.h
@@ -29,7 +29,7 @@ extern "C" {
/***** START SECTION CONFIG *****/
-#define JANET_VERSION "0.1.0"
+#define JANET_VERSION "0.2.0"
#ifndef JANET_BUILD
#define JANET_BUILD "local"
@@ -204,6 +204,8 @@ extern "C" {
/* Names of all of the types */
extern const char *const janet_type_names[16];
+extern const char *const janet_signal_names[14];
+extern const char *const janet_status_names[16];
/* Fiber signals */
typedef enum {
@@ -667,8 +669,8 @@ struct JanetKV {
/* Source mapping structure for a bytecode instruction */
struct JanetSourceMapping {
- int32_t line;
- int32_t column;
+ int32_t start;
+ int32_t end;
};
/* A function definition. Contains information needed to instantiate closures. */
@@ -731,8 +733,7 @@ struct JanetParser {
size_t statecap;
size_t bufcount;
size_t bufcap;
- size_t line;
- size_t col;
+ size_t offset;
int lookback;
};
@@ -937,6 +938,13 @@ JANET_API Janet janet_scan_number(const uint8_t *src, int32_t len);
JANET_API int32_t janet_scan_integer(const uint8_t *str, int32_t len, int *err);
JANET_API double janet_scan_real(const uint8_t *str, int32_t len, int *err);
+/* Debugging */
+JANET_API int janet_debug_break(JanetFuncDef *def, int32_t pc);
+JANET_API int janet_debug_unbreak(JanetFuncDef *def, int32_t pc);
+JANET_API int janet_debug_find(
+ JanetFuncDef **def_out, int32_t *pc_out,
+ const uint8_t *source, int32_t offset);
+
/* Array functions */
JANET_API JanetArray *janet_array(int32_t capacity);
JANET_API JanetArray *janet_array_n(const Janet *elements, int32_t n);
@@ -967,8 +975,8 @@ JANET_API int janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x);
#define janet_tuple_raw(t) ((int32_t *)(t) - 4)
#define janet_tuple_length(t) (janet_tuple_raw(t)[0])
#define janet_tuple_hash(t) ((janet_tuple_raw(t)[1]))
-#define janet_tuple_sm_line(t) ((janet_tuple_raw(t)[2]))
-#define janet_tuple_sm_col(t) ((janet_tuple_raw(t)[3]))
+#define janet_tuple_sm_start(t) ((janet_tuple_raw(t)[2]))
+#define janet_tuple_sm_end(t) ((janet_tuple_raw(t)[3]))
JANET_API Janet *janet_tuple_begin(int32_t length);
JANET_API const Janet *janet_tuple_end(Janet *tuple);
JANET_API const Janet *janet_tuple_n(const Janet *values, int32_t n);
diff --git a/src/mainclient/init.janet b/src/mainclient/init.janet
index d82d10fd..25ee876c 100644
--- a/src/mainclient/init.janet
+++ b/src/mainclient/init.janet
@@ -24,12 +24,12 @@
(os/exit 0)
1)
"v" (fn [&] (print janet/version "-" janet/build) (os/exit 0) 1)
- "s" (fn [&] (:= *raw-stdin* true) (:= *should-repl* true) 1)
- "r" (fn [&] (:= *should-repl* true) 1)
- "p" (fn [&] (:= *exit-on-error* false) 1)
- "-" (fn [&] (:= *handleopts* false) 1)
+ "s" (fn [&] (set *raw-stdin* true) (set *should-repl* true) 1)
+ "r" (fn [&] (set *should-repl* true) 1)
+ "p" (fn [&] (set *exit-on-error* false) 1)
+ "-" (fn [&] (set *handleopts* false) 1)
"e" (fn [i &]
- (:= *no-file* false)
+ (set *no-file* false)
(eval (get process/args (+ i 1)))
2)})
@@ -45,7 +45,7 @@
(if (and *handleopts* (= "-" (string/slice arg 0 1)))
(+= i (dohandler (string/slice arg 1 2) i))
(do
- (:= *no-file* false)
+ (set *no-file* false)
(import* _env arg :prefix "" :exit *exit-on-error*)
(++ i))))
@@ -55,6 +55,6 @@
(do
(print (string "Janet " janet/version "-" janet/build " Copyright (C) 2017-2018 Calvin Rose"))
(repl (fn [buf p]
- (def [line] (parser/where p))
- (def prompt (string "janet:" line ":" (parser/state p) "> "))
+ (def offset (parser/where p))
+ (def prompt (string "janet:" offset ":" (parser/state p) "> "))
(getline prompt buf)))))))
diff --git a/src/webclient/webinit.janet b/src/webclient/webinit.janet
index 09ecb2b4..5ef92263 100644
--- a/src/webclient/webinit.janet
+++ b/src/webclient/webinit.janet
@@ -3,8 +3,8 @@
(fiber/new (fn webrepl []
(repl (fn get-line [buf p]
- (def [line] (parser/where p))
- (def prompt (string "janet:" line ":" (parser/state p) "> "))
+ (def offset (parser/where p))
+ (def prompt (string "janet:" offset ":" (parser/state p) "> "))
(repl-yield prompt buf)
(yield)
buf))))
diff --git a/test/helper.janet b/test/helper.janet
index f0478341..2f02847e 100644
--- a/test/helper.janet
+++ b/test/helper.janet
@@ -13,7 +13,7 @@
x)
(defn start-suite [x]
- (:= suite-num x)
+ (set suite-num x)
(print "\nRunning test suite " x " tests...\n"))
(defn end-suite []
diff --git a/test/suite0.janet b/test/suite0.janet
index 957629f5..ad2dac83 100644
--- a/test/suite0.janet
+++ b/test/suite0.janet
@@ -24,8 +24,8 @@
(assert (= 10 (+ 1 2 3 4)) "addition")
(assert (= -8 (- 1 2 3 4)) "subtraction")
(assert (= 24 (* 1 2 3 4)) "multiplication")
-(assert (= 4 (<< 1 2)) "left shift")
-(assert (= 1 (>> 4 2)) "right shift")
+(assert (= 4 (blshift 1 2)) "left shift")
+(assert (= 1 (brshift 4 2)) "right shift")
(assert (< 1 2 3 4 5 6) "less than integers")
(assert (< 1.0 2.0 3.0 4.0 5.0 6.0) "less than reals")
(assert (> 6 5 4 3 2 1) "greater than integers")
@@ -60,10 +60,10 @@
(assert (not false) "false literal")
(assert true "true literal")
(assert (not nil) "nil literal")
-(assert (= 7 (| 3 4)) "bit or")
-(assert (= 0 (& 3 4)) "bit and")
-(assert (= 0xFF (^ 0x0F 0xF0)) "bit xor")
-(assert (= 0xF0 (^ 0xFF 0x0F)) "bit xor 2")
+(assert (= 7 (bor 3 4)) "bit or")
+(assert (= 0 (band 3 4)) "bit and")
+(assert (= 0xFF (bxor 0x0F 0xF0)) "bit xor")
+(assert (= 0xF0 (bxor 0xFF 0x0F)) "bit xor 2")
# Set global variables to prevent some possible compiler optimizations that defeat point of the test
(var zero 0)
@@ -80,7 +80,7 @@
# Mcarthy's 91 function
(var f91 nil)
-(:= f91 (fn [n] (if (> n 100) (- n 10) (f91 (f91 (+ n 11))))))
+(set f91 (fn [n] (if (> n 100) (- n 10) (f91 (f91 (+ n 11))))))
(assert (= 91 (f91 10)) "f91(10) = 91")
(assert (= 91 (f91 11)) "f91(11) = 91")
(assert (= 91 (f91 20)) "f91(20) = 91")
@@ -92,7 +92,7 @@
(assert (= 94 (f91 104)) "f91(104) = 94")
# Fibonacci
-(def fib (do (var fib nil) (:= fib (fn [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))))
+(def fib (do (var fib nil) (set fib (fn [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))))
(def fib2 (fn fib2 [n] (if (< n 2) n (+ (fib2 (- n 1)) (fib2 (- n 2))))))
(assert (= (fib 0) (fib2 0) 0) "fib(0)")
@@ -127,15 +127,15 @@
(var accum 1)
(var count 0)
(while (< count 16)
- (:= accum (<< accum 1))
- (:= count (+ 1 count)))
+ (set accum (blshift accum 1))
+ (set count (+ 1 count)))
(assert (= accum 65536) "loop in closure")))
(var accum 1)
(var count 0)
(while (< count 16)
- (:= accum (<< accum 1))
- (:= count (+ 1 count)))
+ (set accum (blshift accum 1))
+ (set count (+ 1 count)))
(assert (= accum 65536) "loop globally")
(assert (= (struct 1 2 3 4 5 6 7 8) (struct 7 8 5 6 3 4 1 2)) "struct order does not matter 1")
@@ -228,18 +228,18 @@
(def xi (get xs i))
(def yj (get ys j))
(if (< xi yj)
- (do (array/push ret xi) (:= i (+ i 1)))
- (do (array/push ret yj) (:= j (+ j 1)))))
+ (do (array/push ret xi) (set i (+ i 1)))
+ (do (array/push ret yj) (set j (+ j 1)))))
# Push rest of xs
(while (< i xlen)
(def xi (get xs i))
(array/push ret xi)
- (:= i (+ i 1)))
+ (set i (+ i 1)))
# Push rest of ys
(while (< j ylen)
(def yj (get ys j))
(array/push ret yj)
- (:= j (+ j 1)))
+ (set j (+ j 1)))
ret)
(assert (apply <= (merge @[1 3 5] @[2 4 6])) "merge sort merge 1")
@@ -255,7 +255,7 @@
(var count 0)
(while (< count 128)
(put syms (gensym) true)
- (:= count (+ 1 count)))
+ (set count (+ 1 count)))
(assert (= (length syms) 128) "many symbols")))
# Let
diff --git a/test/suite1.janet b/test/suite1.janet
index 43228445..39f6d207 100644
--- a/test/suite1.janet
+++ b/test/suite1.janet
@@ -33,7 +33,7 @@
(defn myfun [x]
(var a 10)
- (:= a (do
+ (set a (do
(def y x)
(if x 8 9))))
@@ -44,7 +44,7 @@
(var good true)
(loop [i :range [0 n]]
(if (not (f))
- (:= good false)))
+ (set good false)))
(assert good e))
(assert-many (fn [] (>= 1 (math/random) 0)) 200 "(random) between 0 and 1")