schala/TODO.md
2021-10-26 01:53:30 -07:00

5.8 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:

  1. 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

  2. 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

General code cleanup

Longer-term Ideas

Language Syntax

  • 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

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 '}'