basic101 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -0
  3. data/Changelog.md +9 -1
  4. data/Gemfile +9 -8
  5. data/Gemfile.lock +66 -53
  6. data/README.md +8 -6
  7. data/VERSION +1 -1
  8. data/basic101.gemspec +688 -0
  9. data/lib/basic101/parser.rb +28 -457
  10. data/lib/basic101/parser/data_statement.rb +20 -0
  11. data/lib/basic101/parser/define_function_statement.rb +18 -0
  12. data/lib/basic101/parser/dim_statement.rb +16 -0
  13. data/lib/basic101/parser/end_statement.rb +11 -0
  14. data/lib/basic101/parser/expression.rb +100 -0
  15. data/lib/basic101/parser/for_statement.rb +17 -0
  16. data/lib/basic101/parser/function_call.rb +13 -0
  17. data/lib/basic101/parser/gosub_statement.rb +12 -0
  18. data/lib/basic101/parser/goto_statement.rb +11 -0
  19. data/lib/basic101/parser/identifier.rb +87 -0
  20. data/lib/basic101/parser/if_statement.rb +20 -0
  21. data/lib/basic101/parser/input_statement.rb +19 -0
  22. data/lib/basic101/parser/let_statement.rb +13 -0
  23. data/lib/basic101/parser/next_statement.rb +16 -0
  24. data/lib/basic101/parser/numeric.rb +34 -0
  25. data/lib/basic101/parser/on_goto_statement.rb +20 -0
  26. data/lib/basic101/parser/print_statement.rb +19 -0
  27. data/lib/basic101/parser/program.rb +17 -0
  28. data/lib/basic101/parser/randomize_statement.rb +11 -0
  29. data/lib/basic101/parser/read_statement.rb +12 -0
  30. data/lib/basic101/parser/reference.rb +36 -0
  31. data/lib/basic101/parser/remark_statement.rb +11 -0
  32. data/lib/basic101/parser/restore_statement.rb +12 -0
  33. data/lib/basic101/parser/return_statement.rb +11 -0
  34. data/lib/basic101/parser/space.rb +23 -0
  35. data/lib/basic101/parser/statements.rb +36 -0
  36. data/lib/basic101/parser/stop_statement.rb +11 -0
  37. data/lib/basic101/parser/string.rb +17 -0
  38. data/test/spec/basic_float_spec.rb +2 -2
  39. data/test/spec/basic_object_spec.rb +1 -1
  40. data/test/spec/basic_string_spec.rb +2 -2
  41. data/test/spec/input_reader_spec.rb +11 -11
  42. data/test/spec/input_spec.rb +5 -5
  43. data/test/spec/output_spec.rb +3 -3
  44. data/test/spec/spec_helper.rb +2 -1
  45. data/test/spec/support/basic_numeric_helpers.rb +3 -3
  46. metadata +82 -34
@@ -0,0 +1,20 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:data_statement) do
6
+ str('DATA') >>
7
+ (space? >> data_item >>
8
+ (space? >> str(',') >>
9
+ space? >> data_item
10
+ ).repeat(0)
11
+ ).as(:data_items)
12
+ end
13
+
14
+ rule(:data_item) do
15
+ float | integer | quoted_string | unquoted_string
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,18 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:define_function_statement) do
6
+ str('DEF').as(:def) >>
7
+ space? >> user_defined_function_identifier.as(:identifier) >>
8
+ (space? >> str('(') >>
9
+ space? >> scalar_reference_list >>
10
+ space? >> str(')')
11
+ ).as(:parameters) >>
12
+ space? >> str('=') >>
13
+ space? >> expression.as(:expression)
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,16 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:dim_statement) do
6
+ str('DIM').as(:dim) >>
7
+ (space? >> array_reference >>
8
+ (space? >> str(',') >>
9
+ space? >> array_reference
10
+ ).repeat(0)
11
+ ).as(:references)
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,11 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:end_statement) do
6
+ str('END').as(:end)
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,100 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:multiply_op) do
6
+ (str('*').as(:multiply) |
7
+ str('/').as(:divide))
8
+ end
9
+
10
+ rule(:addition_op) do
11
+ (str('+').as(:add) |
12
+ str('-').as(:subtract))
13
+ end
14
+
15
+ rule(:comparison_op) do
16
+ (str('=').as(:eq) |
17
+ str('<>').as(:ne) |
18
+ str('>=').as(:ge) |
19
+ str('<=').as(:le)) |
20
+ str('<').as(:lt) |
21
+ str('>').as(:gt)
22
+ end
23
+
24
+ rule(:and_op) do
25
+ str('AND').as(:and)
26
+ end
27
+
28
+ rule(:or_op) do
29
+ str('OR').as(:or)
30
+ end
31
+
32
+ rule(:factor) do
33
+ quoted_string |
34
+ float |
35
+ integer |
36
+ function_call |
37
+ reference |
38
+ str('(') >> space? >> expression >> space? >> str(')')
39
+ end
40
+
41
+ rule(:power) do
42
+ (factor.as(:left) >>
43
+ space? >> str('^').as(:power) >>
44
+ space? >> power.as(:right)) |
45
+ factor
46
+ end
47
+
48
+ rule(:negation) do
49
+ (str('-') >>
50
+ space? >> power).as(:negation) |
51
+ power
52
+ end
53
+
54
+ rule(:term) do
55
+ negation.as(:left) >>
56
+ (space? >> multiply_op.as(:operator) >>
57
+ space? >> negation.as(:right)
58
+ ).repeat(1).as(:operations).maybe
59
+ end
60
+
61
+ rule(:simple_expression) do
62
+ term.as(:left) >>
63
+ (space? >> addition_op.as(:operator) >>
64
+ space? >> term.as(:right)
65
+ ).repeat(1).as(:operations).maybe
66
+ end
67
+
68
+ rule(:comparison_expression) do
69
+ simple_expression.as(:left) >>
70
+ (space? >> comparison_op.as(:operator) >>
71
+ space? >> simple_expression.as(:right)
72
+ ).repeat(1).as(:operations).maybe
73
+ end
74
+
75
+ rule(:not_expression) do
76
+ (str('NOT') >> space? >> comparison_expression).as(:not) |
77
+ comparison_expression
78
+ end
79
+
80
+ rule(:and_expression) do
81
+ not_expression.as(:left) >>
82
+ (space? >> and_op.as(:operator) >>
83
+ space? >> not_expression.as(:right)
84
+ ).repeat(1).as(:operations).maybe
85
+ end
86
+
87
+ rule(:or_expression) do
88
+ and_expression.as(:left) >>
89
+ (space? >> or_op.as(:operator) >>
90
+ space? >> and_expression.as(:right)
91
+ ).repeat(1).as(:operations).maybe
92
+ end
93
+
94
+ rule(:expression) do
95
+ or_expression
96
+ end
97
+
98
+ end
99
+
100
+ end
@@ -0,0 +1,17 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:for_statement) do
6
+ str('FOR') >>
7
+ space? >> scalar_reference.as(:reference) >>
8
+ space? >> str('=') >>
9
+ space? >> expression.as(:from) >>
10
+ space? >> str('TO') >>
11
+ space? >> expression.as(:to) >>
12
+ (space? >> str('STEP') >> space? >> expression).maybe.as(:step)
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,13 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:function_call) do
6
+ function_identifier.as(:function_identifier) >> space? >>
7
+ str('(') >> space? >> argument_list.as(:argument_list) >>
8
+ space? >> str(')')
9
+ end
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,12 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:gosub_statement) do
6
+ str('GOSUB').as(:gosub) >>
7
+ space? >> integer.as(:line_number)
8
+ end
9
+
10
+ end
11
+
12
+ end
@@ -0,0 +1,11 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:goto_statement) do
6
+ str('GOTO').as(:goto) >> space? >> integer
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,87 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:identifier) do
6
+ string_identifier | numeric_identifier
7
+ end
8
+
9
+ rule(:numeric_identifier) do
10
+ base_identifier.as(:numeric_identifier)
11
+ end
12
+
13
+ rule(:string_identifier) do
14
+ (base_identifier >> str('$')).as(:string_identifier)
15
+ end
16
+
17
+ rule(:function_identifier) do
18
+ user_defined_function_identifier |
19
+ built_in_function_identifier
20
+ end
21
+
22
+ rule(:user_defined_function_identifier) do
23
+ (str('FN') >> base_identifier >>
24
+ str('$').maybe).as(:function_identifier)
25
+ end
26
+
27
+ rule(:built_in_function_identifier) do
28
+ (str('ABS') |
29
+ str('ASC') |
30
+ str('CHR$') |
31
+ str('COS') |
32
+ str('EXP') |
33
+ str('INT') |
34
+ str('LEFT$') |
35
+ str('LEN') |
36
+ str('LOG') |
37
+ str('MID$') |
38
+ str('RIGHT$') |
39
+ str('RND') |
40
+ str('SGN') |
41
+ str('SIN') |
42
+ str('SQR') |
43
+ str('STR$') |
44
+ str('TAB') |
45
+ str('TAN') |
46
+ str('VAL')).as(:function_identifier)
47
+ end
48
+
49
+ rule(:base_identifier) do
50
+ (keyword.absent? >> match('[A-Z]')) >>
51
+ (keyword.absent? >> match('[A-Z0-9]')).repeat(0)
52
+ end
53
+
54
+ rule(:keyword) do
55
+ str('AND') |
56
+ str('DATA') |
57
+ str('DEF') |
58
+ str('DIM') |
59
+ str('ELSE') |
60
+ str('ELSE') |
61
+ str('END') |
62
+ str('FOR') |
63
+ str('GOSUB') |
64
+ str('GOTO') |
65
+ str('GOTO') |
66
+ str('IF') |
67
+ str('INPUT') |
68
+ str('LET') |
69
+ str('NEXT') |
70
+ str('NOT') |
71
+ str('ON') |
72
+ str('OR') |
73
+ str('PRINT') |
74
+ str('RANDOMIZE') |
75
+ str('READ') |
76
+ str('REM') |
77
+ str('RESTORE') |
78
+ str('RETURN') |
79
+ str('STEP') |
80
+ str('STOP') |
81
+ str('THEN') |
82
+ str('TO')
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,20 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:if_statement) do
6
+ str('IF').as(:if) >>
7
+ space? >> expression.as(:condition) >>
8
+ (space? >> str('THEN')).maybe >>
9
+ space? >> if_block.as(:then_block) >>
10
+ (space? >> str('ELSE') >> space? >> if_block).maybe.as(:else_block)
11
+ end
12
+
13
+ rule(:if_block) do
14
+ (integer.as(:if_line_number) |
15
+ statements)
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,19 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:input_statement) do
6
+ str('INPUT').as(:input) >>
7
+ (space? >> quoted_string.as(:prompt) >>
8
+ space? >> prompt_delimeter.as(:prompt_delimeter)).maybe >>
9
+ space? >> reference_list.as(:references)
10
+ end
11
+
12
+ rule(:prompt_delimeter) do
13
+ str(';').as(:prompt_delimeter) |
14
+ str(',').as(:null_prompt_delimeter)
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,13 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:let_statement) do
6
+ (str('LET') >> space?).maybe >>
7
+ reference.as(:lvalue) >> space? >>
8
+ str('=') >> space? >> expression.as(:rvalue)
9
+ end
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,16 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:next_statement) do
6
+ str('NEXT').as(:next) >>
7
+ (space? >> reference >>
8
+ (space? >> str(',') >>
9
+ space? >> reference
10
+ ).repeat(0)
11
+ ).maybe.as(:references)
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,34 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:float) do
6
+ (fixed >> exponent.maybe |
7
+ sign.maybe >> decimal >> exponent).as(:float)
8
+ end
9
+
10
+ rule(:integer) do
11
+ (sign.maybe >> decimal).as(:integer)
12
+ end
13
+
14
+ rule(:decimal) do
15
+ match('[0-9]').repeat(1)
16
+ end
17
+
18
+ rule(:sign) do
19
+ match('[+-]')
20
+ end
21
+
22
+ rule(:fixed) do
23
+ sign.maybe >>
24
+ (decimal >> str('.') >> decimal.maybe) |
25
+ (str('.') >> decimal)
26
+ end
27
+
28
+ rule(:exponent) do
29
+ str('E') >> sign.maybe >> decimal
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,20 @@
1
+ module Basic101
2
+
3
+ class Parser < Parslet::Parser
4
+
5
+ rule(:on_goto_statement) do
6
+ str('ON').as(:on_goto) >>
7
+ space? >>expression.as(:expression) >>
8
+ space? >> str('GOTO') >>
9
+ (
10
+ space? >> integer >>
11
+ (
12
+ space? >> str(',') >>
13
+ space? >> integer
14
+ ).repeat(0)
15
+ ).as(:line_numbers)
16
+ end
17
+
18
+ end
19
+
20
+ end