-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfunctions.go
159 lines (141 loc) · 4.05 KB
/
functions.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package main
import (
"crypto/rand"
"errors"
"fmt"
"strconv"
)
// BoiGoFunc defines a function that can be invoked
// by the Boi-lang script
type BoiGoFunc func(*BoiContext, []BoiVar) (BoiVar, error)
// BoiGoFuncScruct defines an interface that can be
// invoked as a function by the Boi-lang script
type BoiGoFuncStruct interface {
Run(*BoiContext, []BoiVar) (BoiVar, error)
}
// BoiGoFunctionAdapter implements the function interface
// that the Boi-lang interpreter requires in order to make
// it possible to invoke an implementor of the BoiGoFunc
// interface
type BoiGoFunctionAdapter struct {
function BoiGoFuncStruct
interpreter *BoiInterpreter
}
func (adapter BoiGoFunctionAdapter) Do(args []BoiVar) error {
context := adapter.interpreter.subContext()
defer adapter.interpreter.returnContext()
returnValue, err := adapter.function.Run(context, args)
if err != nil {
return err
}
adapter.interpreter.context.variables["exit"] = returnValue
return nil
}
// BoiGoFuncAsFuncStruct makes it possible to pass a function
// matching the BoiGoFunc type wherever one might pass an
// implementor of BoiGoFuncStruct (since this is what
// BoiGoFunctionAdapter aggregates)
type BoiGoFuncAsFuncStruct struct {
function BoiGoFunc
}
func (structure BoiGoFuncAsFuncStruct) Run(
ctx *BoiContext, args []BoiVar,
) (
BoiVar, error,
) {
return structure.function(ctx, args)
}
// BoiStatementsFunction implements BoiGoFuncStruct, and runs aggregate
// BoiStatement objects in order.
type BoiStatementsFunction struct {
statements []*BoiStatement
interpreter *BoiInterpreter
}
func NewBoiStatementsFunction(
statements []*BoiStatement,
interpreter *BoiInterpreter,
) *BoiStatementsFunction {
return &BoiStatementsFunction{
statements, interpreter,
}
}
func (f *BoiStatementsFunction) Run(
ctx *BoiContext, args []BoiVar,
) (BoiVar, error) {
for i, val := range args {
ctx.Set(string("arg."+strconv.Itoa(i)), val)
}
for _, stmt := range f.statements {
err := f.interpreter.ExecStmt(stmt)
if err != nil {
return BoiVar{}, err
}
}
exitValue, exists := ctx.variables["exit"]
if !exists {
exitValue = BoiVar{[]byte{}}
}
return exitValue, nil
}
/*
func BoiFuncName(context *BoiContext, args []BoiVar) ([]byte, error) {
return nil, nil
}
*/
func BoiFuncSay(context *BoiContext, args []BoiVar) (BoiVar, error) {
for _, bvar := range args {
fmt.Print(string(bvar.data))
}
fmt.Println()
return BoiVar{}, nil
}
func BoiFuncSet(context *BoiContext, args []BoiVar) (BoiVar, error) {
if len(args) < 2 {
return BoiVar{}, errors.New("set requires 2 parameters")
}
key := string(args[0].data)
//context.parentCtx.variables[key] = args[1]
context.parentCtx.Set(key, args[1])
return args[1], nil
}
func BoiFuncGet(context *BoiContext, args []BoiVar) (BoiVar, error) {
if len(args) < 1 {
return BoiVar{}, errors.New("get requires 1 parameters")
}
key := string(args[0].data)
//context.parentCtx.variables[key] = args[1]
exit, exists := context.parentCtx.Get(key)
if exists {
context.Set("exists", BoiVar{[]byte("true")})
} else {
context.Set("exists", BoiVar{[]byte("false")})
}
return exit, nil
}
// BoiFuncDeclare is similar to BoiFuncSet, but does not require a value
// parameter. It instead initializes the variable to a completely random
// value to **ensure** the application programmer can't make assumptions
// about the value. Adding a value parameter anyway is undefined behaviour.
func BoiFuncDeclare(context *BoiContext, args []BoiVar) (BoiVar, error) {
if len(args) < 1 {
return BoiVar{}, errors.New("one requires 1 parameters")
}
key := string(args[0].data)
//context.parentCtx.variables[key] = args[1]
value := make([]byte, 4)
_, err := rand.Read(value)
if err != nil {
return BoiVar{}, err
}
// We can't use .Set() here, because that tries to find the variable
// in parent scopes.
context.parentCtx.variables[key] = BoiVar{value}
return BoiVar{value}, nil
}
func BoiFuncCat(context *BoiContext, args []BoiVar) (BoiVar, error) {
output := []byte{}
for _, arg := range args {
output = append(output, arg.data...)
}
return BoiVar{output}, nil
}