| 217 | } |
| 218 | |
| 219 | func (p *Program) Evaluate(r io.Reader, w io.Writer, functions map[string]Function) error { |
| 220 | if len(p.Commands) == 0 { |
| 221 | return nil |
| 222 | } |
| 223 | |
| 224 | ctx := &Context{ |
| 225 | Vars: map[string]interface{}{}, |
| 226 | Functions: functions, |
| 227 | Input: r, |
| 228 | Output: w, |
| 229 | } |
| 230 | |
| 231 | for index := 0; index < len(p.Commands); { |
| 232 | cmd := p.Commands[index] |
| 233 | switch { |
| 234 | case cmd.Goto != nil: |
| 235 | cmd := cmd.Goto |
| 236 | next, ok := p.Table[cmd.Line] |
| 237 | if !ok { |
| 238 | return participle.Errorf(cmd.Pos, "invalid line number %d", cmd.Line) |
| 239 | } |
| 240 | index = next.Index |
| 241 | continue |
| 242 | |
| 243 | case cmd.Remark != nil: |
| 244 | |
| 245 | case cmd.Let != nil: |
| 246 | cmd := cmd.Let |
| 247 | value, err := cmd.Value.Evaluate(ctx) |
| 248 | if err != nil { |
| 249 | return err |
| 250 | } |
| 251 | ctx.Vars[cmd.Variable] = value |
| 252 | |
| 253 | case cmd.Print != nil: |
| 254 | cmd := cmd.Print |
| 255 | value, err := cmd.Expression.Evaluate(ctx) |
| 256 | if err != nil { |
| 257 | return err |
| 258 | } |
| 259 | fmt.Fprintln(ctx.Output, value) |
| 260 | |
| 261 | case cmd.Input != nil: |
| 262 | cmd := cmd.Input |
| 263 | var value float64 |
| 264 | _, err := fmt.Fscanln(ctx.Input, &value) |
| 265 | if err != nil { |
| 266 | return participle.Errorf(cmd.Pos, "invalid input: %s", err) |
| 267 | } |
| 268 | ctx.Vars[cmd.Variable] = value |
| 269 | |
| 270 | case cmd.If != nil: |
| 271 | cmd := cmd.If |
| 272 | condition, err := cmd.Condition.Evaluate(ctx) |
| 273 | if err != nil { |
| 274 | return err |
| 275 | } |
| 276 | if test, ok := condition.(bool); ok && test { |