Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add experimental support for macro "functions" #14

Merged
merged 3 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Visp.Compiler/Syntax/LexHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ let specialSymbol (s: string) =
| it when it.Length > 1 && it[0] = '+' && isLetter it[1] -> Some(PROP_PLUS s)
| it when it.Length > 1 && it[0] = '.' && isLetter it[1] -> Some(DOT_METHOD s)
| it when it.Length > 1 && it[0] = '-' && isLetter it[1] -> Some(APPLY_METHOD s)
| "+" -> Some(OP_PLUS)
| "-" -> Some(OP_MINUS)
| "/" -> Some(OP_DIV)
| "*" -> Some(OP_MULT)
| _ -> None

let symbolOrKeyword (s: string) =
Expand Down
13 changes: 12 additions & 1 deletion src/Visp.Compiler/Syntax/SynWriter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,14 @@ module Write =

()

let private writeBodyNoIndent<'a>
(w: SynWriter)
(wrt: SynWriter -> WriteState -> 'a -> unit)
(items: seq<'a>)
=
newline w
writeSeq w WriteState.Body newline wrt items

let private writeBody<'a>
(w: SynWriter)
(wrt: SynWriter -> WriteState -> 'a -> unit)
Expand Down Expand Up @@ -628,7 +636,10 @@ module Write =
if kind = BeginKind.Do then
char w '('

writeBody w writeExpr expr
if kind = BeginKind.Do then
writeBody w writeExpr expr
else
writeBodyNoIndent w writeExpr expr

if kind = BeginKind.Do then
char w ')'
Expand Down
97 changes: 75 additions & 22 deletions src/Visp.Compiler/Transforms/SyntaxMacroExpander.fs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ let (|DiscardPredicate|Not|) (pat: SynMacroPat) =
| SynMacroPat.List([ MatchingText "?discard" true ], _) -> DiscardPredicate
| _ -> Not

let (|SymText|_|) (pat: SynMacroBody) =
match pat with
| SynMacroBody.Symbol it -> Some(it.Text)
| _ -> None

let (|SpecialCall|_|) call (pat: SynMacroBody) =
match pat with
| SynMacroBody.List(k, (SynMacroBody.Symbol sym) :: rest, r) when sym.Text = call ->
Some(k, rest, r)
| _ -> None


let rec private matchesPat (args: SynMacroBody list) (pats: SynMacroPat list) =
// printfn "looking for\n%A\nin\n%A" args pats
// TODO: Determine pattern matching
Expand Down Expand Up @@ -142,38 +154,90 @@ type private TokenizeArgs =
t.mode <- TokenizeMode.Default
t.depth <- 0

let private evaluatePatterns
(body: SynMacroBody)
(pats: Dictionary<string, BoundPatternBody>)
(range: range)
: SynExpr =
type private BoundPats = Dictionary<string, BoundPatternBody>

let private evaluatePatterns (body: SynMacroBody) (pats: BoundPats) (range: range) : SynExpr =


let findPattern bod (pats: Dictionary<string, BoundPatternBody>) =
let findPattern (pats: BoundPats) bod =
match bod with
| SynMacroBody.Symbol sym ->
match pats.TryGetValue(sym.Text) with
| false, _ -> None
| true, n -> Some(n)
| _ -> None

let rec getBody (pats: BoundPats) bod =
match findPattern pats bod with
| Some(it) ->
match it with
| BoundPatternBody.Item it -> getBody pats it
| BoundPatternBody.List lst -> lst |> List.map (getBody pats) |> List.concat
| None -> [ bod ]

let rec tokenize
(pats: Dictionary<string, BoundPatternBody>)
(pats: BoundPats)
(res: ResizeArray<token>)
(args: TokenizeArgs)
(f: SynMacroBody)
(currentBody: SynMacroBody)
=

let handleSymbol args text =
match args.mode with
| TokenizeMode.Macro -> res.Add(SYMBOL text)
| TokenizeMode.Default ->
let tok = LexHelpers.symbolOrKeyword text

match tok with
| MACRO_NAME _
| SYNTAX_MACRO -> args.StartMacro()
| _ -> ()

res.Add(tok)

let bound_tokenize = tokenize pats res args

match findPattern f pats with
match findPattern pats currentBody with
| Some(pat) ->
match pat with
| BoundPatternBody.Item(it) -> bound_tokenize it
| BoundPatternBody.List(lst) -> lst |> List.iter bound_tokenize

| None ->
match f with
match currentBody with
| SpecialCall "m-concat-id" (_, call_args, _) ->
match call_args with
| arg1 :: arg2 :: [] ->
match ((getBody pats arg1), (getBody pats arg2)) with
| ([ SymText lhs ], [ SymText rhs ]) -> handleSymbol args (lhs + rhs)
| _ -> failwithf "todo concat id %A" call_args

| _ -> failwithf "todo concat id %A" call_args

()
| SpecialCall "m-map" (_, call_args, _) ->
match call_args with
| (SymText method) :: (SynMacroBody.List(_, list, _)) :: [] ->
let argz = list |> List.map (getBody pats) |> List.concat

match method with
| "m-name" ->
let names =
argz
|> List.choose (function
| SynMacroBody.Symbol it -> Some(it)
| SynMacroBody.List(_, SynMacroBody.Symbol it :: _, _) -> Some(it)
| SynMacroBody.Ellipsis _ -> None
| it -> failwithf "unsupported m-map %A" it)
|> List.map _.Text

names |> List.iter (handleSymbol args)

| _ -> failwithf "unsupported m-map method: %A %A" method call_args

| _ -> failwithf "todo concat id %A" call_args

()
| SynMacroBody.List(kind, lst, _) ->
res.Add(openToken kind)

Expand Down Expand Up @@ -218,18 +282,7 @@ let private evaluatePatterns

()

| SynMacroBody.Symbol sym ->
match args.mode with
| TokenizeMode.Macro -> res.Add(SYMBOL sym.Text)
| TokenizeMode.Default ->
let tok = LexHelpers.symbolOrKeyword sym.Text

match tok with
| MACRO_NAME _
| SYNTAX_MACRO -> args.StartMacro()
| _ -> ()

res.Add(tok)
| SynMacroBody.Symbol sym -> handleSymbol args sym.Text

use pooled = PooledList.GetPooled<token>()
let res = pooled.Value
Expand Down
10 changes: 10 additions & 0 deletions tests/Visp.Compiler.UnitTests/ParsingTests.generated.fs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ module ``tests_macros_struct-example-1`` =
[<Fact>]
let ``can parse`` () = TestUtils.runTest "tests/macros/struct-example-1.visp"

[<VerifyXunit.UsesVerify>]
module ``tests_macros_count-exprs-0`` =
[<Fact>]
let ``can parse`` () = TestUtils.runTest "tests/macros/count-exprs-0.visp"

[<VerifyXunit.UsesVerify>]
module ``tests_macros_syntax-macro-2`` =
[<Fact>]
Expand All @@ -210,6 +215,11 @@ module ``tests_macros_cond-macro-1`` =
[<Fact>]
let ``can parse`` () = TestUtils.runTest "tests/macros/cond-macro-1.visp"

[<VerifyXunit.UsesVerify>]
module ``tests_macros_struct-macro-2`` =
[<Fact>]
let ``can parse`` () = TestUtils.runTest "tests/macros/struct-macro-2.visp"

[<VerifyXunit.UsesVerify>]
module ``tests_macros_chars-in-macros-0`` =
[<Fact>]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,33 @@ let visp_result_todo =
then
// line 22 @"cond-macro-1.visp"

// line 22 @"cond-macro-1.visp"
printfn ("body here1")
// line 22 @"cond-macro-1.visp"
printfn ("body here2")
()
// line 22 @"cond-macro-1.visp"
printfn ("body here1")
// line 22 @"cond-macro-1.visp"
printfn ("body here2")
()
else
// line 22 @"cond-macro-1.visp"
if CoreMethods.isTruthy(
CoreMethods.``lt``(1, 0))
then
// line 22 @"cond-macro-1.visp"

// line 22 @"cond-macro-1.visp"
printfn ("here1")
// line 22 @"cond-macro-1.visp"
printfn ("here2")
// line 22 @"cond-macro-1.visp"
printfn ("here1")
// line 22 @"cond-macro-1.visp"
printfn ("here2")
else
// line 22 @"cond-macro-1.visp"
if CoreMethods.isTruthy(
true)
then
// line 22 @"cond-macro-1.visp"

// line 22 @"cond-macro-1.visp"
printfn ("default1")
// line 22 @"cond-macro-1.visp"
printfn ("default2")
// line 22 @"cond-macro-1.visp"
printfn ("default1")
// line 22 @"cond-macro-1.visp"
printfn ("default2")
else
// line 22 @"cond-macro-1.visp"
failwith ("unreachable")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This file is auto-generated

#nowarn "0020" // unused results from functions

open Visp.Runtime.Library

let state = { Todo = () }
// line 8 @"count-exprs-0.visp"
let macro_CountExprsExampleTest1 = "__MACRO_INIT__"
// line 15 @"count-exprs-0.visp"
let exprCount =
// line 15 @"count-exprs-0.visp"
(1) +
((1) +
((1) +
((1) +
((1) +
((1) +
(1))))))
// line 17 @"count-exprs-0.visp"
let visp_result_todo =
// line 17 @"count-exprs-0.visp"
printfn ("exprs: %A") (exprCount)
// line 17 @"count-exprs-0.visp"
printfn ("%A") (visp_result_todo)

Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ type Range (start: int64, len: int64) =
// line 8 @"struct-example-1.visp"
member _.End =
// line 8 @"struct-example-1.visp"
CoreMethods.``add``(start, len)
(start) +
(len)
// line 8 @"struct-example-1.visp"
member d.Offset v =
// line 8 @"struct-example-1.visp"
CoreMethods.``sub``(v, (d.Start))
v - (d.Start)

// line 8 @"struct-example-1.visp"
member d.Contains v =
Expand Down Expand Up @@ -78,13 +79,14 @@ type SourceDestMap (dest: int64, src: int64, len: int64) =
((d.Src).Contains src))
then
// line 29 @"struct-example-1.visp"
CoreMethods.``add``(d
(d
|> (fun a1 ->
// line 29 @"struct-example-1.visp"
(a1.Dest))
|> (fun a1 ->
// line 29 @"struct-example-1.visp"
(a1.Start)), ((d.Src).Offset src))
(a1.Start))) +
(((d.Src).Offset src))
else
// line 29 @"struct-example-1.visp"
if CoreMethods.isTruthy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ type Example (x: int, y: int) =
// line 16 @"struct-macro-0.visp"
member d.Sum () =
// line 16 @"struct-macro-0.visp"
CoreMethods.``add``((d.X), (d.Y))
((d.X)) +
((d.Y))

// line 22 @"struct-macro-0.visp"
let instance =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// This file is auto-generated

#nowarn "0020" // unused results from functions

open Visp.Runtime.Library

let state = { Todo = () }
// line 8 @"struct-macro-2.visp"
let macro_MyStruct2 = "__MACRO_INIT__"
// line 22 @"struct-macro-2.visp"

[<Struct()>]
// line 22 @"struct-macro-2.visp"
type Example (x: int, y: int) =
// line 22 @"struct-macro-2.visp"
member _.X =
x
// line 22 @"struct-macro-2.visp"
member _.Y =
y
// line 22 @"struct-macro-2.visp"
member d.Sum () =
// line 22 @"struct-macro-2.visp"
((d.X)) +
((d.Y))

// line 22 @"struct-macro-2.visp"
let mkExample x y =
// line 22 @"struct-macro-2.visp"
(new Example(x, y))

// line 28 @"struct-macro-2.visp"
let instance =
// line 28 @"struct-macro-2.visp"
mkExample (1) (2)
// line 30 @"struct-macro-2.visp"
printfn ("Example Struct is %A") (instance)
// line 31 @"struct-macro-2.visp"
printfn ("Example IsValueType %A") (instance
|> (fun a1 ->
// line 31 @"struct-macro-2.visp"
(a1.GetType()))
|> (fun a1 ->
// line 31 @"struct-macro-2.visp"
(a1.IsValueType)))
// line 32 @"struct-macro-2.visp"
let visp_result_todo =
// line 32 @"struct-macro-2.visp"
printfn ("Example Result is %i") ((instance.Sum()))
// line 32 @"struct-macro-2.visp"
printfn ("%A") (visp_result_todo)

Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ let name arg =
match arg with
| (a, b) ->
// line 21 @"syntax-macro-0.visp"
CoreMethods.``add``(a, b)
(a) +
(b)
| _ ->
0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ let lambda =
match arg with
| (a , b) ->
// line 28 @"syntax-macro-2.visp"
CoreMethods.``add``(a, b))
(a) +
(b))
// line 29 @"syntax-macro-2.visp"
let named arg =
// line 29 @"syntax-macro-2.visp"
match arg with
| (a , b) ->
// line 29 @"syntax-macro-2.visp"
CoreMethods.``add``(a, b)
(a) +
(b)

// line 32 @"syntax-macro-2.visp"
printfn ("lambda: %i") (lambda (1, 2))
Expand Down
Loading