Skip to content

Commit

Permalink
"1:20pm. Came back for a bit so I can have breakfast. I did figure ou…
Browse files Browse the repository at this point in the history
…t a bunch of thing. Let me continue reading vol 4 of the GGO novel for a bit and I will get back to chaos meditating.

1:35pm. Ok, let me get back to bed. I do not feel like writing about what comes next just yet. I need to focus on raising my tension internally.

4pm. The weather was bad recently so my timing to get away from the screen for a while was good.

4:05pm. Ok, I've realized various things. Let me put my thoughts together.

1) Type wildcard.
2) Paired symbol pattern.
3) Semantic group enum.
4) Reference dictionary extension.

These 4 things should not mean anything to anybody just dropping in, but let me go at them in turn. Let me do some programming here. Apart from the last one, I can do the first 3 items quickly enough now.

Let me do the second one first.

```fs
    let pat_symbol_paired =
        (many1 (read_symbol_paired .>>. opt root_pattern_pair) |>> fun l ->
            match l |> List.map (function a, b -> a, defaultArg b (PatVar a)) |> List.unzip with
            | (k :: k' as keys), v ->
                let body keys =
                    let b = Text.StringBuilder()
                    List.iter (fun (x : string) -> b.Append(x).Append('_') |> ignore) keys
                    List.reduceBack (fun a b -> PatPair(a,b)) (PatSymbol (b.ToString()) :: v)
                if Char.IsLower(k,0) then body keys else body (to_lower k :: k') |> PatUnbox
            | _ -> failwith "Compiler error: Should be at least one key in symbol_paired_process_pattern"
            )
        <|> pat_pair
```

Ah, I did not fuck this up. Ok, good. I was afraid for a bit there.

You know, I should do the same on the value level.

Having to write `(Some: x)` with a parenth instead of normally does not sit right with me. It should be right after statements.

I'll have to do an indentation based check. I'll do the same thing in types and get rid of the flag.

4:15pm. I think my problem with paired symbol is that I am obsessesed with opening a new scope every time I enter one, but I can just restrain myself a little when it comes to this.

Yeah.

Ok...let me work on that then for the rest of the day. I should be able to manage this.

```fs
and root_type allow_metavars allow_value_exprs allow_forall allow_symbol_paired d =
```

Agh, this flag.

```fs
        let symbol_paired d =
            let i = col d
            (pipe2 (read_symbol_paired_big .>>. next) (many (indent i (<=) read_symbol_paired .>>. next)) (fun a b ->
                let k,v = List.unzip ((to_lower (fst a), snd a) :: b)
                let b = Text.StringBuilder()
                List.iter (fun (x : string) -> b.Append(x).Append('_') |> ignore) k
                List.reduceBack (fun a b -> RawTPair(a,b)) (RawTSymbol (b.ToString()) :: v))) d
```

Let me do it like this.

...Hmmm, just like with operators, let me relax the rule just a bit.

```fs
(pipe2 (read_symbol_paired_big .>>. next) (many (indent (i-1) (<=) read_symbol_paired .>>. next)) (fun a b ->
```

This will allow me to write things like...

```
(a: 1
b: 2)
```

Now let me do the same thing...

No actually, let me make it the same the pattern.

```fs
    let symbol_paired d =
        let i = col d
        let next = forall
        (pipe2 (read_symbol_paired_big .>>. next) (many (indent (i-1) (<=) read_symbol_paired .>>. next)) (fun a b ->
            let k,v = List.unzip ((to_lower (fst a), snd a) :: b)
            let b = Text.StringBuilder()
            List.iter (fun (x : string) -> b.Append(x).Append('_') |> ignore) k
            List.reduceBack (fun a b -> RawTPair(a,b)) (RawTSymbol (b.ToString()) :: v))
        <|> next) d
    symbol_paired d
```

This is kind of the rough work of language design. I have to optimize for the commonest use case.

```fs
    let symbol_paired d =
        let next = operators
        let i = col d
        let pat = indent (i-1) (<=) read_symbol_paired .>>. opt next
        (many1 pat |>> fun l ->
            let a,b = List.unzip l
            let x,x' = match a with x::x' -> x,x' | _ -> failwith "Compiler error: Expected `many1 pat` to produce an element."
            let is_upper = Char.IsUpper(x, 0)
            let a = if is_upper then to_lower x :: x' else a
            let b = List.map2 (fun a b -> defaultArg b (v a)) a b
            let a =
                let sb = Text.StringBuilder()
                a |> List.iter (fun x -> sb.Append(x).Append('_') |> ignore)
                sb.ToString()
            if is_upper then ap (v a) (List.reduceBack (binop TupleCreate) b)
            else List.reduceBack (binop TupleCreate) (RawSymbolCreate a :: b)) d

    let statements d =
        let next = symbol_paired
```

This should be good.

Ah, no wait, I forgot the alternative.

```fs
    let symbol_paired d =
        let next = operators
        let i = col d
        let pat = indent (i-1) (<=) read_symbol_paired .>>. opt next
        ((many1 pat |>> fun l ->
            let a,b = List.unzip l
            let x,x' = match a with x::x' -> x,x' | _ -> failwith "Compiler error: Expected `many1 pat` to produce an element."
            let is_upper = Char.IsUpper(x, 0)
            let a = if is_upper then to_lower x :: x' else a
            let b = List.map2 (fun a b -> defaultArg b (v a)) a b
            let a =
                let sb = Text.StringBuilder()
                a |> List.iter (fun x -> sb.Append(x).Append('_') |> ignore)
                sb.ToString()
            if is_upper then ap (v a) (List.reduceBack (binop TupleCreate) b)
            else List.reduceBack (binop TupleCreate) (RawSymbolCreate a :: b))
        <|> next) d
```

I meant to do this.

Now let me move to testing this.

4:35pm.

```
instance bind option a : forall b. x f =
    match x with
    | Some: x => Some: f x : Some: i32
                 a: q
    | None => None
```

Hmmm, why does this parse?

Ah, it probably gets parsed as two statements.

```
instance bind option a : forall b. x f =
    match x with
    | Some: x => (Some: f x : Some: i32)
                 a: q
    | None => None
```

Like this.

Ok, it makes sense.

```
let g x =
    a: 1
    inl x = 1
   a: 2
```

That last token being dedented gives the compiler error message, even though it is really not a compiler error.

Forget that.

```fs
else Error [fst s.tokens.[s.Index], ExpectedEob]
```

Let me replace the unknown error with this.

Ok, let me go with this. It is not ideal, but I do not know of a better way.

That is paired symbols done again. Now their parsing is consistent everywhere.

4:50pm. Next.

1) Type wildcard.

I forgot about wildcards in types.

```fs
and RawTExpr =
    | RawTWildcard
```

Let me add this to the union type.

```fs
and root_type allow_metavars allow_value_exprs allow_forall d =
    let next = root_type allow_metavars allow_value_exprs allow_forall
    let allow_wildcard = allow_metavars || allow_forall
    let cases d =
        let wildcard d = if allow_wildcard then (skip_keyword SpecWildcard >>% RawTWildcard) d else Error []
```

Plugged this in.

Let me try it out.

```
let g x =
    typecase i32 with
    | _ => 1
```

Yeah, it works. Nice.

Let me get to item number 3.

3) Semantic group enum.

```fs
let token_groups = function
    | TokVar _ -> 0 // variable
    | TokSymbol _ | TokSymbolPaired _ -> 1 // symbol
    | TokValue(LitString _) -> 2 // string
    | TokValue _ | TokDefaultValue -> 3 // number
    | TokOperator _ -> 4 // operator
    | TokUnaryOperator _ -> 5 // unary operator
    | TokComment _ -> 6 // comment
    | TokKeyword _ -> 7 // keyword
    | TokParenthesis _ -> 8 // parenthesis
```

Finally found this.

This should be an enum.

```fs
type SemanticTokenLegend =
| variable = 0
| symbol = 1
| string = 2
| number = 3
| operator = 4
| unaryOperator = 5
| comment = 6
| keyword = 7
| parenthesis = 8
| typeVariable = 9
```

Let me plug this in.

...Hmmm, I was sure there was a type variable in there somewhere.

```fs
type SemanticTokenLegend =
| variable = 0
| symbol = 1
| string = 2
| number = 3
| operator = 4
| unary_operator = 5
| comment = 6
| keyword = 7
| parenthesis = 8
| type_variable = 9
```

It is also strange, I thought that `_` was forbidden in ids, but I see that it is now.

```
typeParameter
```

Ah, there was this. But is not in the other table, so nevermind it.

I got this out of the way, and I even added to the legend.

5:05pm.

4) Reference dictionary extension.

The next thing is this. What I am going to do here is finish the semantic tokenization properly.

I thought of doing this work in different places, but I want parsing to be consistent.

I thought it might be more elegant to do a proper pass to get variable information based off ranges, but in the end, the easisest way to get proper grouping is to just hack the parser and be done with it.

Let me do it.

```fs
let token_groups (overrides : Collections.Generic.Dictionary<string,SemanticTokenLegend>) =
    let f def x = match overrides.TryGetValue(x) with true,v -> v | _ -> def
    function
    | TokVar x -> f SemanticTokenLegend.variable x
    | TokSymbol x | TokSymbolPaired x -> f SemanticTokenLegend.symbol x
    | TokValue(LitString _) -> SemanticTokenLegend.string
    | TokValue _ | TokDefaultValue -> SemanticTokenLegend.number
    | TokOperator _ -> SemanticTokenLegend.operator
    | TokUnaryOperator _ -> SemanticTokenLegend.unary_operator
    | TokComment _ -> SemanticTokenLegend.comment
    | TokKeyword _ -> SemanticTokenLegend.keyword
    | TokParenthesis _ -> SemanticTokenLegend.parenthesis
```

Here is the plan.

5:10pm.

```fs
            | GetRange((a,b),res) -> // It is assumed that a.character = 0 and b.character = length of the line
                let from, near_to = a.line, b.line+1
                vscode_tokens from (lines.GetRange(from,near_to-from).ToArray()) |> IVar.fill res
```

Agh, this is not good. How do I get the dictionary here?

```fs
let token_groups = function
    | TokVar (_,r) | TokSymbol (_,r) | TokSymbolPaired (_,r) -> !r
```

Let me do this.

5:25pm.

```fs
        let var = read_var' |>> fun (x,r) ->
            r := SemanticTokenLegend.type_variable
            match x with
```

This is hacky as shit, but it will work. Let me test this first extension.

```fs
let g (x : qwe) =
    1 : i32
```

Great, the type variable is in green here.

Now I just need to take care of the paired symbol patterns.

```fs
let g (x : qwe) =
    inl f = function
        | a:b:c: => 1
    ()
```

Let me start with the stuff in root pattern.

```fs
    let pat_symbol_paired =
        (many1 (read_symbol_paired' .>>. opt root_pattern_pair) |>> fun l ->
            let f ((a,r),b) = a, Option.defaultWith (fun () -> r := SemanticTokenLegend.variable; PatVar a) b
            match l |> List.map f |> List.unzip with
```

This should do it here.

```fs
let g (x:e) =
    inl f = function
        | a:x b:q c: => 1
    ()
```

Yeah, it works correctly. Let me also do it in `root_term` and I am done.

5:35pm.

```
let g (x:e) =
    inl f = function
        | a: b:q c: => 1
    q: 1 w: e: r: x
```

This is great. Everything here is highlighted correct. `w:` is in blue and `r:` is in yellow.

5:40pm. Now my beautiful and clean token array which was functionaly pure before has the stentch of mutation on it, and code is coupled in ways it should not be, but nevermind this.

I am not getting graded on functional purity, but on real life functionality.

I picked the minimum effort path to full semantic highlighting and I'll be proud of it. Doing it this way is probably the most efficient way as well.

5:45pm. This mutation I've inserted into the AST does not affect the actual functionality of the compiler so it should be fine.

It would just be too much effort to write extra code and triangulate the overrides by ranges.

Let me stop here for the day. It is lunch time."
  • Loading branch information
mrakgr committed Jul 24, 2020
1 parent 24d9ee0 commit 4923f93
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 87 deletions.
116 changes: 69 additions & 47 deletions The Spiral Language v0.2 (typechecking)/BlockParsing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,22 @@ let skip_unary_op t d =

let read_var d =
try_current d <| function
| p, TokVar t' -> skip d; ok d (p,t')
| p, TokVar(t',r) -> skip d; ok d (p,t')
| p, _ -> Error [p, ExpectedVar]

let read_var' d =
try_current d <| function
| p, TokVar(t',r) -> skip d; ok d (p,(t',r))
| p, _ -> Error [p, ExpectedVar]

let read_big_var d =
try_current d <| function
| p, TokVar t' when Char.IsUpper(t',0) -> skip d; ok d (p,t')
| p, TokVar(t',r) when Char.IsUpper(t',0) -> skip d; ok d (p,t')
| p, _ -> Error [p, ExpectedBigVar]

let read_small_var d =
try_current d <| function
| p, TokVar t' when Char.IsUpper(t',0) = false -> skip d; ok d (p,t')
| p, TokVar(t',r) when Char.IsUpper(t',0) = false -> skip d; ok d (p,t')
| p, _ -> Error [p, ExpectedSmallVar]

let read_value d =
Expand All @@ -130,20 +135,25 @@ let read_default_value d =

let read_symbol_paired d =
try_current d <| function
| p, TokSymbolPaired t' -> skip d; ok d (p,t')
| p, TokSymbolPaired(t',r) -> skip d; ok d (p,t')
| p, _ -> Error [p, ExpectedSymbolPaired]

let read_symbol_paired' d =
try_current d <| function
| p, TokSymbolPaired(t',r) -> skip d; ok d (p,(t',r))
| p, _ -> Error [p, ExpectedSymbolPaired]

let to_lower (x : string) = Char.ToLower(x.[0]).ToString() + x.[1..]
let read_symbol_paired_big d =
try_current d <| function
| p, TokSymbolPaired t' ->
| p, TokSymbolPaired(t',r) ->
if Char.IsUpper(t',0) then skip d; ok d (p, t')
else Error [p, SymbolPairedShouldStartWithUppercase]
| p, _ -> Error [p, ExpectedSymbolPaired]

let read_symbol d =
try_current d <| function
| p, TokSymbol t' -> skip d; Ok(t')
| p, TokSymbol(t',r) -> skip d; Ok(t')
| p, _ -> Error [p, ExpectedSymbol]

let skip_parenthesis a b d =
Expand Down Expand Up @@ -316,6 +326,7 @@ and RawExpr =
| RawTypecase of RawTExpr * (RawTExpr * RawExpr) []
| RawModuleOpen of VarString * SymbolString list * on_succ: RawExpr
and RawTExpr =
| RawTWildcard
| RawTMetaVar of VarString
| RawTVar of VarString
| RawTPair of RawTExpr * RawTExpr
Expand Down Expand Up @@ -543,13 +554,14 @@ and root_pattern s =
(pat_rounds + pat_nominal + pat_wildcard + pat_dyn + pat_value + pat_record + pat_symbol + pat_active) s

let pat_type =
pipe2 body (opt (skip_op ":" >>. fun d -> root_type false (d.is_top_down = false) d.is_top_down true d))
pipe2 body (opt (skip_op ":" >>. fun d -> root_type false (d.is_top_down = false) d.is_top_down d))
(fun a -> function Some b -> PatAnnot(a,b) | None -> a)
let pat_and = sepBy1 pat_type (skip_op "&") |>> List.reduce (fun a b -> PatAnd(a,b))
let pat_pair = pat_pair pat_and
let pat_symbol_paired =
(many1 (read_symbol_paired .>>. opt root_pattern_pair) |>> fun l ->
match l |> List.map (function a, b -> a, defaultArg b (PatVar a)) |> List.unzip with
(many1 (read_symbol_paired' .>>. opt root_pattern_pair) |>> fun l ->
let f ((a,r),b) = a, Option.defaultWith (fun () -> r := SemanticTokenLegend.variable; PatVar a) b
match l |> List.map f |> List.unzip with
| (k :: k' as keys), v ->
let body keys =
let b = Text.StringBuilder()
Expand All @@ -568,15 +580,19 @@ and root_pattern_var d =
(pat_var + pat_wildcard + pat_dyn + peek_open_parenthesis root_pattern) d
and root_pattern_pair d = pat_pair root_pattern_var d

and root_type allow_metavars allow_value_exprs allow_forall allow_symbol_paired d =
let next = root_type allow_metavars allow_value_exprs allow_forall true
and root_type allow_metavars allow_value_exprs allow_forall d =
let next = root_type allow_metavars allow_value_exprs allow_forall
let allow_wildcard = allow_metavars || allow_forall
let cases d =
let wildcard d = if allow_wildcard then (skip_keyword SpecWildcard >>% RawTWildcard) d else Error []
let metavar d = if allow_metavars then (skip_unary_op "~" >>. read_var |>> RawTMetaVar) d else Error []
let term d = if allow_value_exprs then (skip_unary_op "`" >>. ((read_var |>> RawV) <|> rounds root_term) |>> RawTTerm) d else Error []
let record = curlies (sepBy ((record_var .>> skip_op ":") .>>. next) (skip_op ";")) |>> (Map.ofList >> RawTRecord)
let symbol = read_symbol |>> RawTSymbol

let var = read_var |>> function
let var = read_var' |>> fun (x,r) ->
r := SemanticTokenLegend.type_variable
match x with
| "i8" -> RawTPrim Int8T
| "i16" -> RawTPrim Int16T
| "i32" -> RawTPrim Int32T
Expand All @@ -592,16 +608,9 @@ and root_type allow_metavars allow_value_exprs allow_forall allow_symbol_paired
| "char" -> RawTPrim CharT
| x when Char.IsUpper(x,0) -> RawTPair(RawTSymbol(to_lower x), RawTB)
| x -> RawTVar x
let symbol_paired d =
if allow_symbol_paired = false then Error [] else
(pipe2 (read_symbol_paired_big .>>. next) (many (read_symbol_paired .>>. next)) (fun a b ->
let k,v = List.unzip ((to_lower (fst a), snd a) :: b)
let b = Text.StringBuilder()
List.iter (fun (x : string) -> b.Append(x).Append('_') |> ignore) k
List.reduceBack (fun a b -> RawTPair(a,b)) (RawTSymbol (b.ToString()) :: v))) d
let parenths = rounds (next <|>% RawTB)
let (+) = alt (index d)
(symbol_paired + term + metavar + var + parenths + record + symbol) d
(wildcard + term + metavar + var + parenths + record + symbol) d
let apply d =
(pipe2 cases (many (indent (col d) (<) cases))
(fun a b -> List.reduce (fun a b -> match a with RawTVar "array" -> RawTArray b | _ -> RawTApply(a,b)) (a :: b))) d
Expand All @@ -610,32 +619,26 @@ and root_type allow_metavars allow_value_exprs allow_forall allow_symbol_paired
let forall d =
if allow_forall then (pipe2 (forall <|>% []) functions (List.foldBack (fun x s -> RawTForall(x,s)))) d
else functions d
forall d
let symbol_paired d =
let i = col d
let next = forall
(pipe2 (read_symbol_paired_big .>>. next) (many (indent (i-1) (<=) read_symbol_paired .>>. next)) (fun a b ->
let k,v = List.unzip ((to_lower (fst a), snd a) :: b)
let b = Text.StringBuilder()
List.iter (fun (x : string) -> b.Append(x).Append('_') |> ignore) k
List.reduceBack (fun a b -> RawTPair(a,b)) (RawTSymbol (b.ToString()) :: v))
<|> next) d
symbol_paired d

and root_term d =
let rec expressions d =
let next = root_term
let case_var = read_var |>> fun x -> if Char.IsUpper(x,0) then ap (v (to_lower x)) RawB else v x

let case_symbol_paired =
let pat = read_symbol_paired .>>. opt next
many1 pat |>> fun l ->
let a,b = List.unzip l
let x,x' = match a with x::x' -> x,x' | _ -> failwith "Compiler error: Expected `many1 pat` to produce an element."
let is_upper = Char.IsUpper(x, 0)
let a = if is_upper then to_lower x :: x' else a
let b = List.map2 (fun a b -> defaultArg b (v a)) a b
let a =
let sb = Text.StringBuilder()
a |> List.iter (fun x -> sb.Append(x).Append('_') |> ignore)
sb.ToString()
if is_upper then ap (v a) (List.reduceBack (binop TupleCreate) b)
else List.reduceBack (binop TupleCreate) (RawSymbolCreate a :: b)

let case_rounds =
rounds (fun d ->
let (+) = alt (index d)
((read_op |>> v) + case_symbol_paired + next + fun _ -> Ok B) d)
((read_op |>> v) + next + fun _ -> Ok B) d)

let case_fun =
(skip_keyword SpecFun >>. many1 (range root_pattern_pair) .>>. (skip_op "=>" >>. next))
Expand Down Expand Up @@ -680,9 +683,9 @@ and root_term d =
let case_typecase =
let clauses d =
let bar = bar (col d)
(optional bar >>. sepBy1 (root_type true false false true .>>. (skip_op "=>" >>. next)) bar) d
(optional bar >>. sepBy1 (root_type true false false .>>. (skip_op "=>" >>. next)) bar) d

range ((skip_keyword SpecTypecase >>. root_type false true false true .>> skip_keyword SpecWith) .>>. clauses)
range ((skip_keyword SpecTypecase >>. root_type false true false .>> skip_keyword SpecWith) .>>. clauses)
>>= (fun (r, (a, b)) d ->
if d.is_top_down then Error [r,TypecaseNotAllowed]
else Ok(RawTypecase(a,List.toArray b))
Expand Down Expand Up @@ -716,7 +719,7 @@ and root_term d =

let case_unary_op =
read_unary_op >>= fun a d ->
let type_expr d = (((read_small_var |>> RawTVar) <|> (rounds (fun d -> root_type false (d.is_top_down = false) d.is_top_down true d))) |>> RawType) d
let type_expr d = (((read_small_var |>> RawTVar) <|> (rounds (fun d -> root_type false (d.is_top_down = false) d.is_top_down d))) |>> RawType) d
match a with
| "!!!!" ->
(range read_big_var .>>. (rounds (sepBy1 expressions (skip_op ",")))
Expand Down Expand Up @@ -769,12 +772,31 @@ and root_term d =
(term >>= loop) d

pipe2 (tdop Int32.MinValue)
(opt (indent (i-1) (<=) (skip_op ":") >>. indent i (<=) (fun d -> root_type false (d.is_top_down = false) d.is_top_down false d)))
(opt (indent (i-1) (<=) (skip_op ":") >>. indent i (<=) (fun d -> root_type false (d.is_top_down = false) d.is_top_down d)))
(fun a -> function Some b -> RawAnnot(a,b) | _ -> a)
d

let statements d =
let symbol_paired d =
let next = operators
let i = col d
let pat = indent (i-1) (<=) read_symbol_paired' .>>. opt next
((many1 pat |>> fun l ->
let a,b = List.unzip l
let b = List.map2 (fun (a,r) b -> Option.defaultWith (fun () -> r := SemanticTokenLegend.variable; v a) b) a b
let a = List.map fst a
let x,x' = match a with x::x' -> x,x' | _ -> failwith "Compiler error: Expected `many1 pat` to produce an element."
let is_upper = Char.IsUpper(x, 0)
let a = if is_upper then to_lower x :: x' else a
let a =
let sb = Text.StringBuilder()
a |> List.iter (fun x -> sb.Append(x).Append('_') |> ignore)
sb.ToString()
if is_upper then ap (v a) (List.reduceBack (binop TupleCreate) b)
else List.reduceBack (binop TupleCreate) (RawSymbolCreate a :: b))
<|> next) d

let statements d =
let next = symbol_paired
let inl_or_let =
(inl_or_let root_term root_pattern_pair .>>. many (and_inl_or_let root_term root_pattern_pair))
>>= fun x _ ->
Expand Down Expand Up @@ -839,13 +861,13 @@ let top_inl_or_let = inl_or_let root_term root_pattern_pair >>= fun x _ -> top_i
let top_union =
let clauses d =
let bar = bar (col d)
(optional bar >>. sepBy1 (root_type false false false true) bar) d
(optional bar >>. sepBy1 (root_type false false false) bar) d

(skip_keyword SpecUnion >>. many forall_var .>> skip_op "=") .>>. clauses |>> TopUnion

let top_nominal = (skip_keyword SpecNominal >>. many forall_var .>> skip_op "=") .>>. root_type false true false true |>> TopNominal
let top_prototype = tuple4 (skip_keyword SpecPrototype >>. read_small_var) read_small_var (many forall_var) (skip_op ":" >>. root_type false false true true) |>> TopPrototype
let top_type = tuple3 (skip_keyword SpecType >>. read_small_var) (many forall_var) (skip_op "=" >>. root_type false false false true) |>> TopType
let top_nominal = (skip_keyword SpecNominal >>. many forall_var .>> skip_op "=") .>>. root_type false true false |>> TopNominal
let top_prototype = tuple4 (skip_keyword SpecPrototype >>. read_small_var) read_small_var (many forall_var) (skip_op ":" >>. root_type false false true) |>> TopPrototype
let top_type = tuple3 (skip_keyword SpecType >>. read_small_var) (many forall_var) (skip_op "=" >>. root_type false false false) |>> TopType
let top_instance =
tuple5 (skip_keyword SpecInstance >>. read_small_var) (read_small_var .>>. many forall_var)
(skip_op ":" >>. forall <|>% []) (many (range root_pattern_pair))
Expand Down Expand Up @@ -873,7 +895,7 @@ let parse (s : Env) =
| Ok _ as x -> if s.Index = s.tokens.Length then x else Error [fst s.tokens.[s.Index], ExpectedEob]
| Error [] ->
if s.Index = s.tokens.Length then Error [fst (Array.last s.tokens), UnexpectedEob]
else Error [fst s.tokens.[s.Index], UnknownError]
else Error [fst s.tokens.[s.Index], ExpectedEob]
| Error _ as l -> l
else
Error [({line=0; character=0}, {line=0; character=1}), ExpectedAtLeastOneToken]
46 changes: 29 additions & 17 deletions The Spiral Language v0.2 (typechecking)/Tokenize.fs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,22 @@ type Literal =
| LitString of string
| LitChar of char

type SemanticTokenLegend =
| variable = 0
| symbol = 1
| string = 2
| number = 3
| operator = 4
| unary_operator = 5
| comment = 6
| keyword = 7
| parenthesis = 8
| type_variable = 9

type SpiralToken =
| TokVar of string
| TokSymbol of string
| TokSymbolPaired of string
| TokVar of string * SemanticTokenLegend ref
| TokSymbol of string * SemanticTokenLegend ref
| TokSymbolPaired of string * SemanticTokenLegend ref
| TokValue of Literal
| TokDefaultValue of string
| TokOperator of string
Expand All @@ -66,15 +78,14 @@ type SpiralToken =
| TokParenthesis of Parenthesis * ParenthesisState

let token_groups = function
| TokVar _ -> 0 // variable
| TokSymbol _ | TokSymbolPaired _ -> 1 // symbol
| TokValue(LitString _) -> 2 // string
| TokValue _ | TokDefaultValue -> 3 // number
| TokOperator _ -> 4 // operator
| TokUnaryOperator _ -> 5 // unary operator
| TokComment _ -> 6 // comment
| TokKeyword _ -> 7 // keyword
| TokParenthesis _ -> 8 // parenthesis
| TokVar (_,r) | TokSymbol (_,r) | TokSymbolPaired (_,r) -> !r
| TokValue(LitString _) -> SemanticTokenLegend.string
| TokValue _ | TokDefaultValue -> SemanticTokenLegend.number
| TokOperator _ -> SemanticTokenLegend.operator
| TokUnaryOperator _ -> SemanticTokenLegend.unary_operator
| TokComment _ -> SemanticTokenLegend.comment
| TokKeyword _ -> SemanticTokenLegend.keyword
| TokParenthesis _ -> SemanticTokenLegend.parenthesis

let is_small_var_char_starting c = Char.IsLower c || c = '_'
let is_var_char c = Char.IsLetterOrDigit c || c = '_' || c = '''
Expand Down Expand Up @@ -103,7 +114,7 @@ let var (s: Tokenizer) =
let from = s.from
let ok x = ({from=from; nearTo=s.from}, x)
let body x =
skip ':' s (fun () -> TokSymbolPaired(x) |> ok)
skip ':' s (fun () -> TokSymbolPaired(x,ref SemanticTokenLegend.symbol) |> ok)
(fun () ->
let f x = TokKeyword(x)
match x with
Expand All @@ -124,7 +135,7 @@ let var (s: Tokenizer) =
| "open" -> f SpecOpen | "_" -> f SpecWildcard
| "prototype" -> f SpecPrototype | "instance" -> f SpecInstance
| "true" -> TokValue(LitBool true) | "false" -> TokValue(LitBool false)
| x -> TokVar(x)
| x -> TokVar(x,ref SemanticTokenLegend.variable)
|> ok
)

Expand Down Expand Up @@ -176,10 +187,11 @@ let symbol s =
let from = s.from
let f x = ({from=from; nearTo=s.from}, x)

let symbol x = TokSymbol(x,ref SemanticTokenLegend.symbol)
let x = peek s
let x' = peek' s 1
if x = '.' && x' = '(' then inc' 2 s; ((many1SatisfyL is_operator_char "operator") .>> skip_char ')' |>> (TokSymbol >> f) .>> spaces) s
elif x = '.' && is_var_char_starting x' then inc s; ((many1SatisfyL is_var_char "variable") |>> (TokSymbol >> f) .>> spaces) s
if x = '.' && x' = '(' then inc' 2 s; ((many1SatisfyL is_operator_char "operator") .>> skip_char ')' |>> (symbol >> f) .>> spaces) s
elif x = '.' && is_var_char_starting x' then inc s; ((many1SatisfyL is_var_char "variable") |>> (symbol >> f) .>> spaces) s
else error_char from "symbol"

let comment (s : Tokenizer) =
Expand Down Expand Up @@ -314,7 +326,7 @@ let vscode_tokens line_delta (lines : LineToken [] []) =
let toks = ResizeArray()
lines |> Array.fold (fun line_delta tok ->
tok |> Array.fold (fun (line_delta,from_prev) (r,x) ->
toks.AddRange [|line_delta; r.from-from_prev; r.nearTo-r.from; token_groups x; 0|]
toks.AddRange [|line_delta; r.from-from_prev; r.nearTo-r.from; int (token_groups x); 0|]
0, r.from
) (line_delta, 0)
|> fst |> ((+) 1)
Expand Down
5 changes: 5 additions & 0 deletions VS Code Plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
"id": "unary_operator",
"superType": "class",
"description": "An unary operator."
},
{
"id": "type_variable",
"superType": "type",
"description": "A type variable."
}
]
},
Expand Down
2 changes: 1 addition & 1 deletion VS Code Plugin/spiral/src/a.spi
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ prototype bind m a : forall b. m a -> (a -> m b) -> m b

instance bind option a : forall b. x f =
match x with
| Some: x => (Some: f x)
| Some: x => Some: 2
| None => None

inl rec f x = x
Expand Down
25 changes: 4 additions & 21 deletions VS Code Plugin/spiral/src/b.spi
Original file line number Diff line number Diff line change
@@ -1,21 +1,4 @@
// asd
inl f x = y

// qwe
inl g = 12
dasdqw
as

// qwe
inl g = -12
dasdqw
as
a + -2
// qwe qwe
inl gqew = .qwe 12
dasdq
as


// A slightly big function
let Big = let q = 2 in Some(f q x 0)
let g (x:e) =
inl f = function
| a: b:q c: => 1
q: 1 w: e: r: x
2 changes: 1 addition & 1 deletion VS Code Plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export const activate = async (ctx: ExtensionContext) => {
languages.registerDocumentRangeSemanticTokensProvider(
{ language: 'spiral'},
new SpiralTokens(),
new SemanticTokensLegend(['variable','symbol','string','number','operator','unary_operator','comment','keyword','parenthesis'])
new SemanticTokensLegend(['variable','symbol','string','number','operator','unary_operator','comment','keyword','parenthesis','type_variable'])
)
)
}

0 comments on commit 4923f93

Please sign in to comment.