loxxy 0.0.4 → 0.0.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5383d6eb1725f5c53bb343e46d763f18d9d69f6b010241dbc4a93c18f949a6f
4
- data.tar.gz: 286f213ab01ebec8061a9f25c86c6f28be064891880e06942a0d6d86b4210fcb
3
+ metadata.gz: 5db00fee0e8e7ef89a48cacc4e9ad0baf7ae5ee2cb419ba76964199bd7552199
4
+ data.tar.gz: ddb8e9c7ac267f32bed3f77ada05a6af38a872b5f892452a496b17522b608977
5
5
  SHA512:
6
- metadata.gz: 32d447c7dbe6593ad0002ad383a917561c82da22cbf70b4102d0eaa389cf92196e03ee14ab1cc160f530b1c96a1e259db8e7923e2de81322fc854898fa306d49
7
- data.tar.gz: 245d4c9e255b7bb9d8602ab103367d7f83baf516db61f5a9192945ffa689027eb9f5f7a282e7052bca6b9e904cd6f6ed956d61ea949e02b7916f100033ebd9ec
6
+ metadata.gz: 44e0049b0bc01e5d35bed7b91c32a7a3b977e6ba4e806439958bad2dc8aae7ead017a310c8523bd4cb628c14951946981bee42f4001d68b701159fcdaff53419
7
+ data.tar.gz: c90236a82f0a4872b209b8462d5f13377815fd4fc41babf256ff4894ea6900e343c6f192194e1b713cb9f8a8d2bffc326e7ea4f00726193e0a792dc9e1457e41
@@ -1,6 +1,7 @@
1
1
  AllCops:
2
2
  Exclude:
3
3
  - 'exp/**/*'
4
+ - 'demo/**/*'
4
5
 
5
6
  Layout/ArgumentAlignment:
6
7
  Enabled: false
@@ -55,6 +56,9 @@ Layout/MultilineMethodCallBraceLayout:
55
56
 
56
57
  Layout/SpaceAroundOperators:
57
58
  Enabled: true
59
+
60
+ Layout/SpaceBeforeBrackets:
61
+ Enabled: true
58
62
 
59
63
  Layout/SpaceInsideParens:
60
64
  Enabled: true
@@ -70,6 +74,9 @@ Layout/TrailingEmptyLines:
70
74
 
71
75
  Layout/TrailingWhitespace:
72
76
  Enabled: true
77
+
78
+ Lint/AmbiguousAssignment:
79
+ Enabled: true
73
80
 
74
81
  Lint/DuplicateBranch:
75
82
  Enabled: true
@@ -226,6 +233,9 @@ Style/GuardClause:
226
233
 
227
234
  Style/HashEachMethods:
228
235
  Enabled: true
236
+
237
+ Style/HashExcept:
238
+ Enabled: true
229
239
 
230
240
  Style/HashTransformKeys:
231
241
  Enabled: true
@@ -0,0 +1,6 @@
1
+ --exclude examples --exclude features --exclude spec
2
+ --no-private
3
+ --markup markdown
4
+ -
5
+ CHANGELOG.md
6
+ LICENSE.txt
@@ -1,3 +1,10 @@
1
+ ## [0.0.5] - 2021-01-02
2
+ - Improved example in `README.md`, code re-styling to please `Rubocop` 1.7
3
+
4
+ ## Changed
5
+ - Code re-styling to please `Rubocop` 1.7
6
+ - File `README.md` Improved example with better parse tree visualization.
7
+
1
8
  ## [0.0.4] - 2021-01-01
2
9
  - A first parser implementation able to parse Lox source code.
3
10
 
data/README.md CHANGED
@@ -13,6 +13,8 @@ a simple language used in Bob Nystrom's online book [Crafting Interpreters](http
13
13
  - [DONE] Scanner (tokenizer)
14
14
  - [DONE] Raw parser. It parses Lox programs and generates a parse tree.
15
15
  - [TODO] Tailored parser for generating AST (Abstract Syntax Tree)
16
+ - [TODO] Custom AST builder class
17
+ - [TODO] Hierarchy classes for representing Lox expressions in AST
16
18
  - [TODO] Interpreter or transpiler
17
19
 
18
20
 
@@ -34,11 +36,45 @@ base_parser = Loxxy::FrontEnd::RawParser.new
34
36
  # Now parse the input into a concrete parse tree...
35
37
  ptree = base_parser.parse(lox_input)
36
38
 
37
- # Dump the parse tree contents...
38
- p ptree # Lengthy (unwieldy) output
39
+ # Display the parse tree thanks to Rley formatters...
40
+ visitor = Rley::ParseTreeVisitor.new(ptree)
41
+ tree_formatter = Rley::Formatter::Asciitree.new($stdout)
42
+ tree_formatter.render(visitor)
39
43
  ```
40
44
 
41
- Soon, the `loxxy`will host another, tailored parser, that will generate
45
+ This is the output produced by the above example:
46
+ ```
47
+ program
48
+ +-- declaration_star
49
+ | +-- declaration_star
50
+ | +-- declaration
51
+ | +-- statement
52
+ | +-- printStmt
53
+ | +-- PRINT: 'print'
54
+ | +-- expression
55
+ | | +-- assignment
56
+ | | +-- logic_or
57
+ | | +-- logic_and
58
+ | | | +-- equality
59
+ | | | | +-- comparison
60
+ | | | | | +-- term
61
+ | | | | | | +-- factor
62
+ | | | | | | | +-- unary
63
+ | | | | | | | | +-- call
64
+ | | | | | | | | +-- primary
65
+ | | | | | | | | | +-- STRING: '"Hello, world!"'
66
+ | | | | | | | | +-- refinement_star
67
+ | | | | | | | +-- multiplicative_star
68
+ | | | | | | +-- additive_star
69
+ | | | | | +-- comparisonTest_star
70
+ | | | | +-- equalityTest_star
71
+ | | | +-- conjunct_star
72
+ | | +-- disjunct_star
73
+ | +-- SEMICOLON: ';'
74
+ +-- EOF: ''
75
+ ```
76
+
77
+ Soon, the `loxxy` will host another, tailored parser, that will generate
42
78
  abstract syntax tree which much more convenient for further processing
43
79
  (like implementing an interpreter).
44
80
 
@@ -8,15 +8,14 @@ module Loxxy
8
8
  class BuiltinDatatype
9
9
  # @return [Object] The Ruby representation
10
10
  attr_reader :value
11
-
11
+
12
12
  # Constructor. Initialize a Lox value from one of its built-in data type.
13
13
  def initialize(aValue)
14
14
  @value = validated_value(aValue)
15
15
  end
16
-
17
-
16
+
18
17
  protected
19
-
18
+
20
19
  def validated_value(aValue)
21
20
  aValue
22
21
  end
@@ -8,13 +8,13 @@ module Loxxy
8
8
  # Class for representing a Lox false value.
9
9
  class False < Boolean
10
10
  include Singleton # Make a singleton class
11
-
11
+
12
12
  # Build the sole instance
13
13
  def initialize
14
14
  super(false)
15
15
  end
16
16
  end # class
17
-
18
- False.instance.freeze # Make the sole instance immutable
17
+
18
+ False.instance.freeze # Make the sole instance immutable
19
19
  end # module
20
20
  end # module
@@ -6,12 +6,6 @@ module Loxxy
6
6
  module Datatype
7
7
  # Class for representing a Lox string of characters value.
8
8
  class LXString < BuiltinDatatype
9
-
10
- # Build the sole instance
11
- def initialize(aValue)
12
- super(aValue)
13
- end
14
-
15
9
  # Compare a Lox String with another Lox (or genuine Ruby) String
16
10
  # @param other [Datatype::LxString, String]
17
11
  # @return [Boolean]
@@ -22,7 +16,8 @@ module Loxxy
22
16
  when String
23
17
  value == other
24
18
  else
25
- raise StandardError, 'Cannot compare a #{self.class} with #{other.class}'
19
+ err_msg = "Cannot compare a #{self.class} with #{other.class}"
20
+ raise StandardError, err_msg
26
21
  end
27
22
  end
28
23
 
@@ -34,8 +29,8 @@ module Loxxy
34
29
  end
35
30
 
36
31
  # Remove double quotes delimiter
37
- aValue.gsub(/(^")|("$)/, '')
32
+ aValue.gsub(/(^")|("$)/, '')
38
33
  end
39
34
  end # class
40
35
  end # module
41
- end # module
36
+ end # module
@@ -8,13 +8,13 @@ module Loxxy
8
8
  # Class for representing a Lox nil "value".
9
9
  class Nil < BuiltinDatatype
10
10
  include Singleton # Make a singleton class
11
-
11
+
12
12
  # Build the sole instance
13
13
  def initialize
14
14
  super(nil)
15
15
  end
16
16
  end # class
17
-
18
- Nil.instance.freeze # Make the sole instance immutable
17
+
18
+ Nil.instance.freeze # Make the sole instance immutable
19
19
  end # module
20
20
  end # module
@@ -6,19 +6,11 @@ module Loxxy
6
6
  module Datatype
7
7
  # Class for representing a Lox numeric value.
8
8
  class Number < BuiltinDatatype
9
-
10
- # Build the sole instance
11
- def initialize(aValue)
12
- super(aValue)
13
- end
14
-
15
9
  protected
16
10
 
17
11
  def validated_value(aValue)
18
12
  case aValue
19
- when Integer
20
- result = aValue
21
- when Numeric
13
+ when Integer, Numeric
22
14
  result = aValue
23
15
  when /^-?\d+$/
24
16
  result = aValue.to_i
@@ -32,4 +24,4 @@ module Loxxy
32
24
  end
33
25
  end # class
34
26
  end # module
35
- end # module
27
+ end # module
@@ -8,13 +8,13 @@ module Loxxy
8
8
  # Class for representing a Lox true value.
9
9
  class True < Boolean
10
10
  include Singleton # Make a singleton class
11
-
11
+
12
12
  # Build the sole instance
13
13
  def initialize
14
14
  super(true)
15
- end
15
+ end
16
16
  end # class
17
-
18
- True.instance.freeze # Make the sole instance immutable
17
+
18
+ True.instance.freeze # Make the sole instance immutable
19
19
  end # module
20
20
  end # module
@@ -131,7 +131,7 @@ module Loxxy
131
131
  rule('primary' => 'IDENTIFIER')
132
132
  rule('primary' => 'LEFT_PAREN expression RIGHT_PAREN')
133
133
  rule('primary' => 'SUPER DOT IDENTIFIER')
134
-
134
+
135
135
  # Utility rules
136
136
  rule('function' => 'IDENTIFIER LEFT_PAREN params_opt RIGHT_PAREN block')
137
137
  rule('params_opt' => 'parameters')
@@ -142,11 +142,10 @@ module Loxxy
142
142
  rule('arguments_opt' => [])
143
143
  rule('arguments' => 'arguments COMMA expression')
144
144
  rule('arguments' => 'expression')
145
-
146
145
  end
147
146
 
148
- # And now build the grammar and make it accessible via a constant
149
- # @return [Rley::Syntax::Grammar]
150
- Grammar = builder.grammar
147
+ # And now build the grammar and make it accessible via a constant
148
+ # @return [Rley::Syntax::Grammar]
149
+ Grammar = builder.grammar
151
150
  end # module
152
151
  end # module
@@ -14,7 +14,7 @@ module Loxxy
14
14
  # @param theLexeme [String] the lexeme (= piece of text from input)
15
15
  # @param aTerminal [Rley::Syntax::Terminal, String]
16
16
  # The terminal symbol corresponding to the lexeme.
17
- # @param aPosition [Rley::Lexical::Position] The position of lexeme
17
+ # @param aPosition [Rley::Lexical::Position] The position of lexeme
18
18
  # in input text.
19
19
  def initialize(aValue, aLexeme, aTerminal, aPosition)
20
20
  super(aLexeme, aTerminal, aPosition)
@@ -15,7 +15,7 @@ module Loxxy
15
15
  # A TerminalNode is leaf node, that is, it has no child node.
16
16
  # While concrete parse tree nodes can be generated out of the box,
17
17
  # they have the following drawbacks:
18
- # - Generic node classes that aren't always suited for the needs of
18
+ # - Generic node classes that aren't always suited for the needs of
19
19
  # the language being processing.
20
20
  # - Concrete parse tree tend to be deeply nested, which may complicate
21
21
  # further processing.
@@ -27,7 +27,6 @@ module Loxxy
27
27
  # Create a Rley facade object
28
28
  @engine = Rley::Engine.new do |cfg|
29
29
  cfg.diagnose = true
30
- # cfg.repr_builder = SkmBuilder
31
30
  end
32
31
 
33
32
  # Step 1. Load Lox grammar
@@ -52,4 +51,4 @@ module Loxxy
52
51
  end
53
52
  end # class
54
53
  end # module
55
- end # module
54
+ end # module
@@ -50,7 +50,7 @@ module Loxxy
50
50
  '>' => 'GREATER',
51
51
  '>=' => 'GREATER_EQUAL',
52
52
  '<' => 'LESS',
53
- '<=' => 'LESS_EQUAL',
53
+ '<=' => 'LESS_EQUAL'
54
54
  }.freeze
55
55
 
56
56
  # Here are all the implemented Lox keywords (in uppercase)
@@ -99,7 +99,7 @@ module Loxxy
99
99
 
100
100
  token = nil
101
101
 
102
- if "(){},.;/*".include? curr_ch
102
+ if '(){},.;/*'.include? curr_ch
103
103
  # Single delimiter or separator character
104
104
  token = build_token(@@lexeme2name[curr_ch], scanner.getch)
105
105
  elsif (lexeme = scanner.scan(/[+\-](?!\d)/))
@@ -150,7 +150,7 @@ module Loxxy
150
150
  when 'FALSE'
151
151
  value = Datatype::False.instance
152
152
  when 'NIL'
153
- value = Datatype::Nil.instance
153
+ value = Datatype::Nil.instance
154
154
  when 'NUMBER'
155
155
  value = Datatype::Number.new(aLexeme)
156
156
  when 'STRING'
@@ -167,8 +167,6 @@ module Loxxy
167
167
  # Skip non-significant whitespaces and comments.
168
168
  # Advance the scanner until something significant is found.
169
169
  def skip_intertoken_spaces
170
- pre_pos = scanner.pos
171
-
172
170
  loop do
173
171
  ws_found = scanner.skip(/[ \t\f]+/) ? true : false
174
172
  nl_found = scanner.skip(/(?:\r\n)|\r|\n/)
@@ -191,7 +189,7 @@ module Loxxy
191
189
  break unless ws_found || cmt_found
192
190
  end
193
191
 
194
- curr_pos = scanner.pos
192
+ scanner.pos
195
193
  end
196
194
 
197
195
  def skip_block_comment
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Loxxy
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.5'
5
5
  end
@@ -40,8 +40,8 @@ Gem::Specification.new do |spec|
40
40
  spec.version = Loxxy::VERSION
41
41
  spec.authors = ['Dimitri Geshef']
42
42
  spec.email = ['famished.tiger@yahoo.com']
43
- spec.summary = %q{An implementation of the Lox programming language. WIP}
44
- spec.description = %q{An implementation of the Lox programming language. WIP}
43
+ spec.summary = 'An implementation of the Lox programming language. WIP'
44
+ spec.description = 'An implementation of the Lox programming language. WIP'
45
45
  spec.homepage = 'https://github.com/famished-tiger/loxxy'
46
46
  spec.license = 'MIT'
47
47
  spec.required_ruby_version = '~> 2.4'
@@ -1,35 +1,35 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative '../spec_helper' # Use the RSpec framework
4
-
5
- # Load the class under test
6
- require_relative '../../lib/loxxy/datatype/lx_string'
7
-
8
- module Loxxy
9
- module Datatype
10
- describe LXString do
11
- let(:sample_text) { 'some_text' }
12
- subject { LXString.new(sample_text) }
13
-
14
- context 'Initialization:' do
15
- it 'should accept a String value at initialization' do
16
- expect { LXString.new(sample_text) }.not_to raise_error
17
- end
18
-
19
- it 'should know its value' do
20
- expect(subject.value).to eq(sample_text)
21
- end
22
- end
23
-
24
- context 'Provided services:' do
25
- it 'compares with another string' do
26
- expect(subject).to eq(sample_text)
27
- expect(subject).to eq(LXString.new(sample_text.dup))
28
-
29
- expect(subject).not_to eq('')
30
- expect(subject).not_to eq('other-text')
31
- end
32
- end
33
- end # describe
34
- end # module
35
- end # module
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+
5
+ # Load the class under test
6
+ require_relative '../../lib/loxxy/datatype/lx_string'
7
+
8
+ module Loxxy
9
+ module Datatype
10
+ describe LXString do
11
+ let(:sample_text) { 'some_text' }
12
+ subject { LXString.new(sample_text) }
13
+
14
+ context 'Initialization:' do
15
+ it 'should accept a String value at initialization' do
16
+ expect { LXString.new(sample_text) }.not_to raise_error
17
+ end
18
+
19
+ it 'should know its value' do
20
+ expect(subject.value).to eq(sample_text)
21
+ end
22
+ end
23
+
24
+ context 'Provided services:' do
25
+ it 'compares with another string' do
26
+ expect(subject).to eq(sample_text)
27
+ expect(subject).to eq(LXString.new(sample_text.dup))
28
+
29
+ expect(subject).not_to eq('')
30
+ expect(subject).not_to eq('other-text')
31
+ end
32
+ end
33
+ end # describe
34
+ end # module
35
+ end # module
@@ -92,8 +92,10 @@ LOX_END
92
92
  expect(leaf_node.token.value).to eq('Hello, world!')
93
93
  expect(prnt_stmt.subnodes[2]).to be_kind_of(Rley::PTree::TerminalNode)
94
94
  expect(prnt_stmt.subnodes[2].symbol.name).to eq('SEMICOLON')
95
+ expect(eof).to be_kind_of(Rley::PTree::TerminalNode)
96
+ expect(eof.symbol.name).to eq('EOF')
95
97
  end
96
98
  end
97
99
  end # describe
98
100
  end # module
99
- end # module
101
+ end # module
@@ -78,7 +78,7 @@ module Loxxy
78
78
  end
79
79
 
80
80
  it 'should recognize non-datatype keywords' do
81
- keywords =<<-LOX_END
81
+ keywords = <<-LOX_END
82
82
  and class else fun for if or
83
83
  print return super this var while
84
84
  LOX_END
@@ -167,7 +167,7 @@ LOX_END
167
167
  end
168
168
 
169
169
  it 'should recognize string values' do
170
- input =<<-LOX_END
170
+ input = <<-LOX_END
171
171
  ""
172
172
  "string"
173
173
  "123"
@@ -3,7 +3,7 @@
3
3
  require_relative '../lib/loxxy/version/'
4
4
 
5
5
  RSpec.describe Loxxy do
6
- it "has a version number" do
6
+ it 'has a version number' do
7
7
  expect(Loxxy::VERSION).not_to be nil
8
8
  end
9
9
  end
@@ -1,9 +1,11 @@
1
- require "bundler/setup"
2
- require "loxxy"
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'loxxy'
3
5
 
4
6
  RSpec.configure do |config|
5
7
  # Enable flags like --only-failures and --next-failure
6
- config.example_status_persistence_file_path = ".rspec_status"
8
+ config.example_status_persistence_file_path = '.rspec_status'
7
9
 
8
10
  config.expect_with :rspec do |c|
9
11
  # Disable the `should` syntax
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loxxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-01 00:00:00.000000000 Z
11
+ date: 2021-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley
@@ -77,6 +77,7 @@ files:
77
77
  - ".rspec"
78
78
  - ".rubocop.yml"
79
79
  - ".travis.yml"
80
+ - ".yardopts"
80
81
  - CHANGELOG.md
81
82
  - Gemfile
82
83
  - LICENSE.txt