Implemented constructor symbols.
h3rald h3rald@h3rald.com
Fri, 29 Jan 2021 21:28:38 +0000
4 files changed,
45 insertions(+),
3 deletions(-)
M
minpkg/lib/min_lang.nim
→
minpkg/lib/min_lang.nim
@@ -170,8 +170,8 @@ raiseInvalid("Invalid operator definition")
let tv = q.qVal[0] let t = tv.symVal let nv = q.qVal[1] - if not tv.isSymbol or (not ["symbol", "sigil", "typeclass"].contains(t)): - raiseInvalid("Incorrect operator type specified (it must be 'symbol', 'sigil', or 'typeclass' - found '$#')" % tv.symVal) + if not tv.isSymbol or (not ["symbol", "sigil", "typeclass", "constructor"].contains(t)): + raiseInvalid("Incorrect operator type specified (it must be 'symbol', 'sigil', 'constructor', or 'typeclass' - found '$#')" % tv.symVal) if not nv.isSymbol: raiseInvalid("Operator name must be a symbol")@@ -230,6 +230,8 @@ else:
if o: if tv.symVal == "typeclass" and (outExpects.len > 0 or v != "bool"): raiseInvalid("typeclasses can only have one boolean output value") + if tv.symVal == "constructor" and (outExpects.len > 0 or v != "dict"): + raiseInvalid("constructors can only have one dictionary output value") outExpects.add v else: if tv.symVal == "typeclass" and inExpects.len > 0:@@ -286,6 +288,8 @@ # Validate output
for k in 0..outVars.len-1: i.pushSym outVars[k] let x = i.peek + if t == "constructor": + x.objType = n let o = outExpects[k] var r = false; if o.contains("|"):@@ -310,7 +314,7 @@ doc["name"] = %n
doc["kind"] = %t doc["signature"] = %docSig doc["description"] = %i.currSym.docComment.strip - if ["symbol", "typeclass"].contains(t): + if ["symbol", "typeclass", "constructor"].contains(t): if i.scope.symbols.hasKey(n) and i.scope.symbols[n].sealed: raiseUndefined("Attempting to redefine sealed symbol '$1'" % [n]) i.scope.symbols[n] = MinOperator(kind: minProcOp, prc: p, sealed: false, doc: doc)
M
next-release.md
→
next-release.md
@@ -1,6 +1,7 @@
* Implemented "auto-popping" by adding **!** at the end of any symbol. * Removed all symbols ending with **!** as auto-popping will work instead. * Improved contrast and readability of the min web site. +* Extended **operator** to support the creation of constructor symbols. * Now using **dict:http-response** and **dict:http-response** for HTTP requests/responses. * Now using **dict:timeinfo** for time info. * Changed **parse-url** to push a **dict:url** on the stack.
M
site/contents/learn-operators.md
→
site/contents/learn-operators.md
@@ -198,4 +198,30 @@ >
> Generics allow to specify a type as a type union, but the type will remain the same one throughout the same operator call. > By contrast, using the same type union several times within the same signature allows different types to be used in the same call, and that is probably something you dont want! +### Constructors + +The {#link-operator||lang||operator#} operator can also be used to create *constructor* symbols. A constructor is a particular type of operator that is used to create a new typed dictionary. + +Consider the following example: + + ( + constructor point + (num :x num :y ==> dict :out) + ( + {} + x %x + y %y + @out + ) + ) :: + +The operator above creates a `point` constructor symbol that can be used to create a new `dict:point` typed dictionary by popping two numbers from the stack: + + 2 3 point ; {2 :x 3 :y ;point} + +> %note% +> Tip +> +> Except for some native symbols, constructors represent the only way to create new typed dictionaries. The more validations you perform in a constructor, the most effective checking for a specific type using the {#link-operator||logic||type?#} operator will be, as `type?` only checks if a specific type annotation is present on a typed dictionary, nothing else. + {#link-learn||quotations||Quotations#}
M
tests/lang.min
→
tests/lang.min
@@ -276,6 +276,17 @@ (err format-error "expected: natural natural natural-sum" match) *test/assert
(2 3 natural-sum 5 ==) *test/assert ( + constructor test-c + (str :in ==> dict :out) + ( + {} + in %test + @out + ) + ) :: + ("aaa" test-c 'test-c type?) *test/assert + + ( symbol add ((str|num|quot :t) :a t :b ==> t :result) (