aboutsummaryrefslogtreecommitdiff
path: root/run.icl
blob: 385d9875fe86022a26266e41872a6582d5b124fd (plain) (blame)
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
module run

import StdEnv, StdDebug

import GenEq

import Data.Maybe, Data.List
from Data.Func import $

import System.CommandLine, System.GetOpt

import Smurf
import SmurfParse

:: SmurfOpt = Break Char | BreakAll | IFile String | Verbose

derive gEq SmurfOpt
instance == SmurfOpt where == a b = a === b

instance <<< Expr
where
	(<<<) f (Lit s) = f <<< s
	// TODO Rest unimplemented for now

Start :: *World -> *World
Start w
// Options
# (cmd, w) = getCommandLine w
# (opts,_,errs) = getOpt Permute options cmd
| errs <> [] = error errs w
# breakstms
	= if (isMember BreakAll opts)
		[Push (Lit ""), Input, Output, Cat, Head, Tail, Quotify, Put, Get, Exec]
		[fromChar c \\ (Break c) <- opts]
# inputs = [f \\ (IFile f) <- opts]
| length inputs <> 1 = error ["Exactly one input file required"] w
# verbose = isMember Verbose opts
// Read input file
# (_, f, w)  = fopen (hd inputs) FReadText w
# (pgm, f)   = freads f 100000
# (_, w)     = fclose f w
# mbPgm      = parse $ fromString pgm
| isNothing mbPgm = error ["Couldn't parse input file as a Smurf program "] w
# pgm        = fromJust mbPgm
// Start interpreting
# (io, w) = stdio w
# io = loop verbose breakstms pgm zero io
= snd $ fclose io w
where
    loop :: Bool ![Stm] !Program !State !*File -> *File
    loop v brk p st f
	# p = if v (trace (foldl (+++) "" (map toString p) +++ "\n") p) p
    # (mbProgSt, f) = step p st f iofunc
    | isNothing mbProgSt = f <<< "NOTHING!!!\n"
    # (prog, st) = fromJust mbProgSt
    | isEmpty prog
		| v = f <<< "\n---------------------------\n" <<< toString st
		= f
	| not (isBrk prog) = loop v brk prog st f
    # f = f <<< "---> " <<< toString (hd prog) <<< " ? "
    # (cmd, f) = freadline f
	| cmd == "" = loop v [] prog st (f <<< "\n") // Ctrl-D: stop breaking
	# cmd = cmd % (0, size cmd - 2)
    | cmd == "state" = loop v brk prog st (f <<< toString st) // Print state
    = loop v brk prog st f
	where
		isBrk :: Program -> Bool
		isBrk [] = False
		isBrk [(Push _):_] = isMember (Push (Lit "")) brk
		isBrk [stm:_] = isMember stm brk

		iofunc :: *IO *File
		iofunc = IO read show
		where
			read :: *File -> *(Expr, *File)
			read f
				# (s, f) = freadline f
				= (Lit (s % (0, size s - 2)), f)

			show :: Expr *File -> *File
			show s f = f <<< s

	options = [ Option ['i'] ["infile"]
	              (ReqArg IFile "FILE")            "Smurf file"
	          , Option ['b'] ["break"]
	              (ReqArg (\s->Break s.[0]) "STM") "Break on statement"
	          , Option ['B'] ["break-all"]
	              (NoArg BreakAll)                 "Break on all statements"
	          , Option ['v'] ["verbose"]
	              (NoArg Verbose)                  "Print all programs to stderr"
	          ]

	error :: [String] *World -> *World
	error errs w
	# (io, w) = stdio w
	# io = io <<< foldl (+++) "" (intersperse "\n" errs) <<< "\n"
	# io = io <<< usageInfo "CleanSmurf: a Clean Smurf interpreter" options
	# io = io <<< "\n\n"
	= snd $ fclose io w