Skip to content

Commit 7ad8518

Browse files
committed
refactor: separate modules for externals
1 parent 3f927c0 commit 7ad8518

21 files changed

+595
-481
lines changed

app/lithia/cmd/repl.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import (
77
"os"
88

99
cobra "github.com/muesli/coral"
10+
"github.com/vknabel/lithia"
1011
"github.com/vknabel/lithia/reporting"
11-
"github.com/vknabel/lithia/runtime"
1212
)
1313

1414
func init() {
@@ -32,7 +32,7 @@ func runPrompt() {
3232
os.Exit(1)
3333
}
3434
reader := bufio.NewReader(os.Stdin)
35-
inter := runtime.NewInterpreter(importRoot)
35+
inter := lithia.NewDefaultInterpreter(importRoot)
3636
for {
3737
fmt.Print("> ")
3838
line, err := reader.ReadString('\n')

app/lithia/cmd/run.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"path"
77

88
cobra "github.com/muesli/coral"
9-
"github.com/vknabel/lithia/runtime"
9+
"github.com/vknabel/lithia"
1010
)
1111

1212
func init() {
@@ -28,7 +28,7 @@ func runFile(fileName string) {
2828
fmt.Fprint(os.Stderr, err)
2929
os.Exit(1)
3030
}
31-
inter := runtime.NewInterpreter(path.Dir(fileName))
31+
inter := lithia.NewDefaultInterpreter(path.Dir(fileName))
3232
script := string(scriptData) + "\n"
3333
_, err = inter.Interpret(fileName, script)
3434
if err != nil {

external/docs/external-docs.go

+256
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
package docs
2+
3+
import (
4+
"sort"
5+
"strings"
6+
7+
"github.com/vknabel/lithia/ast"
8+
"github.com/vknabel/lithia/runtime"
9+
)
10+
11+
var _ runtime.ExternalDefinition = ExternalDocs{}
12+
13+
type ExternalDocs struct{}
14+
15+
func (e ExternalDocs) Lookup(name string, env *runtime.Environment, decl ast.Decl) (runtime.RuntimeValue, bool) {
16+
switch name {
17+
case "inspect":
18+
return e.docsInspectValueFunction(env, decl), true
19+
default:
20+
return nil, false
21+
}
22+
}
23+
24+
func (e ExternalDocs) docsInspectValueFunction(env *runtime.Environment, decl ast.Decl) runtime.PreludeExternFunction {
25+
return runtime.MakeExternFunction(
26+
decl,
27+
func(args []runtime.Evaluatable) (runtime.RuntimeValue, *runtime.RuntimeError) {
28+
if len(args) != 1 {
29+
return nil, runtime.NewRuntimeErrorf("inspect takes exactly one argument")
30+
}
31+
value, err := args[0].Evaluate()
32+
if err != nil {
33+
return nil, err
34+
}
35+
return docsInspectValue(value, env)
36+
},
37+
)
38+
}
39+
40+
func docsInspectValue(value runtime.RuntimeValue, env *runtime.Environment) (runtime.RuntimeValue, *runtime.RuntimeError) {
41+
switch value := value.(type) {
42+
case runtime.PreludeModule:
43+
sortedKeys := make([]string, 0, len(value.Module.Environment.Scope))
44+
for key := range value.Module.Environment.Scope {
45+
sortedKeys = append(sortedKeys, key)
46+
}
47+
sort.Strings(sortedKeys)
48+
49+
children := make([]runtime.RuntimeValue, 0)
50+
for _, key := range sortedKeys {
51+
decl := value.Module.Environment.Scope[key]
52+
lazyChild, err := decl.Evaluate()
53+
if err != nil {
54+
return nil, err
55+
}
56+
child, err := docsInspectValue(lazyChild, env)
57+
if err != nil {
58+
return nil, err
59+
}
60+
children = append(children, child)
61+
}
62+
63+
childrenList, err := env.MakeEagerList(children)
64+
if err != nil {
65+
return nil, err
66+
}
67+
moduleDocs := []string{}
68+
for _, file := range value.Module.Decl.Files {
69+
for _, decl := range file.Declarations {
70+
if moduleDecl, ok := decl.(ast.DeclModule); ok {
71+
if len(moduleDecl.Docs.Content) == 0 {
72+
continue
73+
}
74+
moduleDocs = append(moduleDocs, moduleDecl.Docs.Content)
75+
}
76+
}
77+
}
78+
return env.MakeDataRuntimeValue("ModuleDocs", map[string]runtime.Evaluatable{
79+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Module.Name)),
80+
"types": runtime.NewConstantRuntimeValue(childrenList),
81+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(strings.Join(moduleDocs, "\n"))),
82+
})
83+
case runtime.PreludeDataDecl:
84+
fieldDocs := make([]runtime.RuntimeValue, 0)
85+
for _, field := range value.Decl.Fields {
86+
params := make([]runtime.RuntimeValue, 0)
87+
for _, param := range field.Parameters {
88+
params = append(params, runtime.PreludeString(param.Name))
89+
}
90+
paramsList, err := env.MakeEagerList(params)
91+
if err != nil {
92+
return nil, err
93+
}
94+
doc, err := env.MakeDataRuntimeValue("DataFieldDocs", map[string]runtime.Evaluatable{
95+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(field.Name)),
96+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(field.Docs.Content)),
97+
"params": runtime.NewConstantRuntimeValue(paramsList),
98+
})
99+
if err != nil {
100+
return nil, err
101+
}
102+
fieldDocs = append(fieldDocs, doc)
103+
}
104+
fieldDocsList, err := env.MakeEagerList(fieldDocs)
105+
if err != nil {
106+
return nil, err
107+
}
108+
return env.MakeDataRuntimeValue("DataDocs", map[string]runtime.Evaluatable{
109+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Decl.Name)),
110+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Decl.Docs.Content)),
111+
"fields": runtime.NewConstantRuntimeValue(fieldDocsList),
112+
})
113+
case runtime.PreludePrimitiveExternType:
114+
fieldDocs := make([]runtime.RuntimeValue, 0)
115+
for _, field := range value.Fields {
116+
params := make([]runtime.RuntimeValue, 0)
117+
for _, param := range field.Parameters {
118+
params = append(params, runtime.PreludeString(param.Name))
119+
}
120+
paramsList, err := env.MakeEagerList(params)
121+
if err != nil {
122+
return nil, err
123+
}
124+
doc, err := env.MakeDataRuntimeValue("ExternFieldDocs", map[string]runtime.Evaluatable{
125+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(field.Name)),
126+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(field.Docs.Content)),
127+
"params": runtime.NewConstantRuntimeValue(paramsList),
128+
})
129+
if err != nil {
130+
return nil, err
131+
}
132+
fieldDocs = append(fieldDocs, doc)
133+
}
134+
fieldDocsList, err := env.MakeEagerList(fieldDocs)
135+
if err != nil {
136+
return nil, err
137+
}
138+
return env.MakeDataRuntimeValue("ExternTypeDocs", map[string]runtime.Evaluatable{
139+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Name)),
140+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Docs.Content)),
141+
"fields": runtime.NewConstantRuntimeValue(fieldDocsList),
142+
})
143+
case runtime.PreludeEnumDecl:
144+
casesDocs := make([]runtime.RuntimeValue, 0)
145+
for _, enumCaseDecl := range value.Decl.Cases {
146+
lazyEnumCase, err := value.LookupCase(string(enumCaseDecl.Name))
147+
if err != nil {
148+
return nil, err
149+
}
150+
151+
enumCase, err := lazyEnumCase.Evaluate()
152+
if err != nil {
153+
return nil, err
154+
}
155+
156+
enumCaseValueDocs, err := docsInspectValue(enumCase, env)
157+
if err != nil {
158+
return nil, err
159+
}
160+
doc, err := env.MakeDataRuntimeValue("EnumCaseDocs", map[string]runtime.Evaluatable{
161+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(enumCaseDecl.Name)),
162+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString("")),
163+
"type": runtime.NewConstantRuntimeValue(enumCaseValueDocs),
164+
})
165+
if err != nil {
166+
return nil, err
167+
}
168+
casesDocs = append(casesDocs, doc)
169+
}
170+
casesList, err := env.MakeEagerList(casesDocs)
171+
if err != nil {
172+
return nil, err
173+
}
174+
return env.MakeDataRuntimeValue("EnumDocs", map[string]runtime.Evaluatable{
175+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Decl.Name)),
176+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Decl.Docs.Content)),
177+
"cases": runtime.NewConstantRuntimeValue(casesList),
178+
})
179+
case runtime.PreludeFuncDecl:
180+
params := make([]runtime.RuntimeValue, 0)
181+
for _, param := range value.Decl.Impl.Parameters {
182+
params = append(params, runtime.PreludeString(param.Name))
183+
}
184+
paramsList, err := env.MakeEagerList(params)
185+
if err != nil {
186+
return nil, err
187+
}
188+
return env.MakeDataRuntimeValue("FunctionDocs", map[string]runtime.Evaluatable{
189+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Decl.Name)),
190+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Decl.Docs.Content)),
191+
"params": runtime.NewConstantRuntimeValue(paramsList),
192+
})
193+
case runtime.PreludeExternFunction:
194+
params := make([]runtime.RuntimeValue, 0)
195+
for _, param := range value.Decl.Parameters {
196+
params = append(params, runtime.PreludeString(param.Name))
197+
}
198+
paramsList, err := env.MakeEagerList(params)
199+
if err != nil {
200+
return nil, err
201+
}
202+
return env.MakeDataRuntimeValue("ExternFunctionDocs", map[string]runtime.Evaluatable{
203+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Decl.Name)),
204+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(value.Decl.Docs.Content)),
205+
"params": runtime.NewConstantRuntimeValue(paramsList),
206+
})
207+
208+
case runtime.RuntimeType:
209+
decl, err := value.Declaration()
210+
if err != nil {
211+
return nil, err
212+
}
213+
switch decl := decl.(type) {
214+
case ast.DeclExternType:
215+
fieldDocs := make([]runtime.RuntimeValue, 0)
216+
for _, field := range decl.Fields {
217+
params := make([]runtime.RuntimeValue, 0)
218+
for _, param := range field.Parameters {
219+
params = append(params, runtime.PreludeString(param.Name))
220+
}
221+
paramsList, err := env.MakeEagerList(params)
222+
if err != nil {
223+
return nil, err
224+
}
225+
doc, err := env.MakeDataRuntimeValue("ExternFieldDocs", map[string]runtime.Evaluatable{
226+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(field.Name)),
227+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(field.Docs.Content)),
228+
"params": runtime.NewConstantRuntimeValue(paramsList),
229+
})
230+
if err != nil {
231+
return nil, err
232+
}
233+
fieldDocs = append(fieldDocs, doc)
234+
}
235+
fieldDocsList, err := env.MakeEagerList(fieldDocs)
236+
if err != nil {
237+
return nil, err
238+
}
239+
return env.MakeDataRuntimeValue("ExternTypeDocs", map[string]runtime.Evaluatable{
240+
"name": runtime.NewConstantRuntimeValue(runtime.PreludeString(decl.Name)),
241+
"docs": runtime.NewConstantRuntimeValue(runtime.PreludeString(decl.Docs.Content)),
242+
"fields": runtime.NewConstantRuntimeValue(fieldDocsList),
243+
})
244+
default:
245+
return env.MakeDataRuntimeValue("None", map[string]runtime.Evaluatable{})
246+
}
247+
// case DocumentedRuntimeValue:
248+
// docs := value.GetDocs()
249+
// return env.MakeDataRuntimeValue("ExternDocs", map[string]Evaluatable{
250+
// "name": runtime.NewConstantRuntimeValue(PreludeString(docs.name)),
251+
// "docs": runtime.NewConstantRuntimeValue(PreludeString(docs.docs)),
252+
// })
253+
default:
254+
return env.MakeDataRuntimeValue("None", map[string]runtime.Evaluatable{})
255+
}
256+
}

runtime/external-fs.go renamed to external/fs/external-fs.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
package runtime
1+
package fs
22

33
import (
44
"os"
55

66
"github.com/vknabel/lithia/ast"
7+
. "github.com/vknabel/lithia/runtime"
78
)
89

910
var _ ExternalDefinition = ExternalFS{}

runtime/external-os.go renamed to external/os/external-os.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
package runtime
1+
package os
22

33
import (
44
"os"
55

66
"github.com/vknabel/lithia/ast"
7+
. "github.com/vknabel/lithia/runtime"
78
)
89

910
var _ ExternalDefinition = ExternalOS{}

external/rx/extern-rx-future-type.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package rx
2+
3+
import (
4+
"github.com/vknabel/lithia/ast"
5+
"github.com/vknabel/lithia/runtime"
6+
)
7+
8+
var _ runtime.RuntimeValue = RxFutureType{}
9+
var _ runtime.DeclRuntimeValue = RxFutureType{}
10+
var _ runtime.RuntimeType = RxFutureType{}
11+
var _ runtime.CallableRuntimeValue = RxFutureType{}
12+
13+
var RxFutureTypeRef = runtime.MakeRuntimeTypeRef("Future", "rx")
14+
15+
type RxFutureType struct {
16+
ast.DeclExternType
17+
}
18+
19+
func (RxFutureType) RuntimeType() runtime.RuntimeTypeRef {
20+
return runtime.PreludeAnyTypeRef
21+
}
22+
23+
func (RxFutureType) String() string {
24+
return RxVariableTypeRef.String()
25+
}
26+
27+
func (t RxFutureType) Declaration() (ast.Decl, *runtime.RuntimeError) {
28+
return t.DeclExternType, nil
29+
}
30+
31+
func (d RxFutureType) HasInstance(value runtime.RuntimeValue) (bool, *runtime.RuntimeError) {
32+
if _, ok := value.(RxVariable); ok {
33+
return true, nil
34+
} else {
35+
return false, nil
36+
}
37+
}
38+
39+
func (RxFutureType) Lookup(member string) (runtime.Evaluatable, *runtime.RuntimeError) {
40+
return nil, runtime.NewRuntimeErrorf("%s is not a member of %s", member, RxVariableTypeRef.String())
41+
}
42+
43+
func (RxFutureType) Arity() int {
44+
return 1
45+
}
46+
47+
func (t RxFutureType) Call(arguments []runtime.Evaluatable, fromExpr ast.Expr) (runtime.RuntimeValue, *runtime.RuntimeError) {
48+
if len(arguments) != 1 {
49+
return nil, runtime.NewRuntimeErrorf("too many arguments for variable type %s", t)
50+
}
51+
receive, err := arguments[0].Evaluate()
52+
if err != nil {
53+
return nil, err.CascadeDecl(t.DeclExternType)
54+
}
55+
if receive, ok := receive.(runtime.CallableRuntimeValue); ok {
56+
return MakeRxFuture(&t, receive), nil
57+
} else {
58+
return nil, runtime.NewRuntimeErrorf("%s is not callable", receive)
59+
}
60+
}
61+
62+
func (t RxFutureType) Source() *ast.Source {
63+
return t.Meta().Source
64+
}

0 commit comments

Comments
 (0)