6.1 KiB
Immediate TODOs / General Code Cleanup
Testing
- Get a test library for running many unit tests working
- Write a human-readable display of the AST
- Make an automatic (macro-based?) system for numbering compiler errors, this should be every type of error
Symbols
-
Add some good printf-debugging impls for SymbolTable-related items
-
the symbol table should probably only be for global definitions (maybe rename it to reflect this?)
-
dealing with variable lookup w/in functions/closures should probably happen in AST -> ReducedAST
- b/c that's where we go from a string name to a canonical ID (for e.g. 2nd param in 3rd enclosing scope)
-
In fact to prove this works, the symbol table shoudl parallelize the process of checking subscopes for local items
-
Old notes on a plan of attack:
-
modify visitor so it can handle scopes -this is needed both to handle import scope correctly -and also to support making FQSNs aware of function parameters
-
Once FQSNs are aware of function parameters, most of the Rc things in eval.rs can go away
Parser
- I think I can restructure the parser to get rid of most instances of expect!, at least at the beginning of a rule
Typechecking
- make a type to represent types rather than relying on string comparisons
- look at https://rickyhan.com/jekyll/update/2018/05/26/hindley-milner-tutorial-rust.html
General code cleanup
- standardize on an error type that isn't String
- implement a visitor pattern for the use of scope_resolver
- maybe implement this twice: 1) the value-returning, no-default one in the haoyi blogpost,
- look at
- https://gitlab.haskell.org/ghc/ghc/wikis/pattern-synonyms
- the non-value-returning, default one like in rustc (cf. https://github.com/rust-unofficial/patterns/blob/master/patterns/visitor.md)
Longer-term Ideas
Language Syntax
- a type like
type Klewos = Klewos { <fields> }
(i.e. a type with exactly one record-like variant) should be writeable astype Klewos = { <fields> }
as a shorthand, and should not require explicit matching. - the
type
declaration should have some kind of GADT-like syntax - use
let
sigil to indicate a variable in a pattern explicitly:
q is MyStruct(let a, Chrono::Trigga) then {
// a is in scope here
}
-
if you have a pattern-match where one variant has a variable and the other lacks it instead of treating this as a type error, promote the bound variable to an option type
-
what if there was something like React jsx syntas built in? i.e. a way to automatically transform some kind of markup into a function call, cf.
<h1 prop="arg">
-> h1(prop=arg) -
implement and test open/use statements
-
Include extensible scala-style
html"string ${var}"
string interpolations -
A neat idea for pattern matching optimization would be if you could match on one of several things in a list ex:
if x {
is (comp, LHSPat, RHSPat) if comp in ["==, "<"] -> ...
}
- Schala should have both currying and default arguments!
fn a(b: Int, c:Int, d:Int = 1) -> Int
a(1,2) : Int
a(1,2,d=2): Int
a(_,1,3) : Int -> Int
a(1,2, c=_): Int -> Int
a(_,_,_) : Int -> Int -> Int -> Int
- scoped types - be able to define a quick enum type scoped to a function or other type for something, that only is meant to be used as a quick bespoke interface between two other things
ex.
type enum {
type enum MySubVariant {
SubVariant1, SubVariant2, etc.
}
Variant1(MySubVariant),
Variant2(...),
}
- inclusive/exclusive range syntax like .. vs ..=
Typechecking
-
cf. the notation mentioned in the cardelli paper, the debug information for the
typechecking
pass should- print the generated type variable for every subexpression in an expression
-
think about idris-related ideas of multiple implementations of a type for an interface (+ vs * impl for monoids, for preorder/inorder/postorder for Foldable)
-
should have an Idris-like
cast To From
function -
something like the swift
Never
type ( https://nshipster.com/never/ ) in the stdlib
Compilation
-
look into Inkwell for rust LLVM bindings
-
look at https://gluon-lang.org/doc/nightly/book/embedding-api.html
Syntax Playground
Trying if-syntax again
//simple if expr
if x == 10 then "a" else "z"
//complex if expr
if x == 10 then {
let a = 1
let b = 2
a + b
} else {
55
}
// different comparison ops
if x {
== 1 then "a"
.isPrime() then "b"
else "c"
}
/* for now disallow `if x == { 1 then ... }`, b/c hard to parse
//simple pattern-matching
if x is Person("Ivan", age) then age else 0
//match-block equivalent
if x {
is Person("Ivan", _) then "Ivan"
is Person(_, age) if age > 13 then "barmitzvah'd"
else "foo"
}
(OLD) Playing around with conditional syntax ideas
- if/match playground
simple if
if x == 1.0 { "a" } else { "b" }
one comparison multiple targets:
if x == { 1.0 -> "a", 2.0 -> "b", else -> "c" }
different comparison operators/ method calls:
if x { == 1.0 -> "a", eq NaN -> "n", .hella() -> "h", else -> "z" }
pattern matching/introducing bindings:
if alice { .age < 18 -> "18", is Person("Alice", age) -> "${age}", else -> "none" }
pattern matching w/ if-let:
if person is Person("Alice", age) { "${age}" } else { "nope" }
-https://soc.github.io/languages/unified-condition-syntax syntax:
if <cond-expr>" then <then-expr> else <else-expr>
if <half-expr> \n <rest-expr1> then <result1-expr> \n <rest-expr2> then <result-expr2> else <result3-expr>
-and rest-exprs (or "targets") can have 'is' for pattern-matching, actually so can a full cond-expr
UNIFIED IF EXPRESSIONS FINAL WORK:
basic syntax:
if_expr := if discriminator '{' (guard_expr)* '}'
guard_expr := pattern 'then' block_or_expr'
pattern := rhs | is_pattern
is_pattern := 'is' ???
rhs := expression | ???
if the only two guard patterns are true and false, then the abbreviated syntax:
'if' discriminator 'then' block_or_expr 'else' block_or_expr
can replace 'if' discriminator '{' 'true' 'then' block_or_expr; 'false' 'then' block_or_expr '}'