123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- RSpec.describe Parser do
- def parse(source)
- Parser.new(Lexer.new(source)).parse
- end
-
- it 'parses null' do
- expect(parse('null;')).to eq([AST::Null.new])
- end
-
- it 'parses booleans' do
- expect(parse('true;')).to eq([AST::Boolean.new(true)])
- expect(parse('false;')).to eq([AST::Boolean.new(false)])
- end
-
- it 'parses numbers' do
- expect(parse('5;')).to eq([AST::Number.new(5.0)])
- end
-
- it 'parses strings' do
- expect(parse('"hello world";')).to eq([AST::String.new('hello world')])
- end
-
- it 'parses addition' do
- expect(parse('1 + 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::ADD,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- end
-
- it 'parses subtraction' do
- expect(parse('1 - 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::SUBTRACT,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- end
-
- it 'parses multiplication' do
- expect(parse('1 * 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::MULTIPLY,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- end
-
- it 'parses division' do
- expect(parse('1 / 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::DIVIDE,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- end
-
- it 'gives multiplication higher precedence than addition' do
- expect(parse('1 + 2 * 3;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::ADD,
- AST::Number.new(1.0),
- AST::Binary.new(
- AST::Operators::MULTIPLY,
- AST::Number.new(2.0),
- AST::Number.new(3.0)
- )
- )
- ]
- )
- end
-
- it 'gives multiplication higher precedence than subtraction' do
- expect(parse('1 - 2 / 3;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::SUBTRACT,
- AST::Number.new(1.0),
- AST::Binary.new(
- AST::Operators::DIVIDE,
- AST::Number.new(2.0),
- AST::Number.new(3.0)
- )
- )
- ]
- )
- end
-
- it 'parses if statement' do
- expect(parse('if true { "true"; }')).to eq(
- [
- AST::Conditional.new(
- [
- AST::Branch.new(
- AST::Boolean.new(true),
- AST::Block.new([AST::String.new('true')])
- )
- ]
- )
- ]
- )
- end
-
- it 'parses if else statement' do
- expect(parse('if true { "true"; } else { "false"; }')).to eq(
- [
- AST::Conditional.new(
- [
- AST::Branch.new(
- AST::Boolean.new(true),
- AST::Block.new([AST::String.new('true')])
- ),
- AST::Branch.new(
- AST::Boolean.new(true),
- AST::Block.new([AST::String.new('false')])
- )
- ]
- )
- ]
- )
- end
-
- it 'parses if elseif else statement' do
- expect(
- parse('if true { "true"; } elseif false { "false"; } else { "neither"; }')
- ).to eq(
- [
- AST::Conditional.new(
- [
- AST::Branch.new(
- AST::Boolean.new(true),
- AST::Block.new([AST::String.new('true')])
- ),
- AST::Branch.new(
- AST::Boolean.new(false),
- AST::Block.new([AST::String.new('false')])
- ),
- AST::Branch.new(
- AST::Boolean.new(true),
- AST::Block.new([AST::String.new('neither')])
- )
- ]
- )
- ]
- )
- end
-
- it 'parses comparisons' do
- expect(parse('1 < 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::LESS_THAN,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- expect(parse('1 > 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::GREATER_THAN,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- expect(parse('1 <= 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::LESS_THAN_OR_EQUAL,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- expect(parse('1 >= 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::GREATER_THAN_OR_EQUAL,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- expect(parse('1 or 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::OR,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- expect(parse('1 and 2;')).to eq(
- [
- AST::Binary.new(
- AST::Operators::AND,
- AST::Number.new(1.0),
- AST::Number.new(2.0)
- )
- ]
- )
- end
-
- it 'parses identifier' do
- expect(parse('x;')).to eq([AST::Identifier.new('x')])
- end
-
- it 'parses variable declaration' do
- expect(parse('let x = 1;')).to eq(
- [
- AST::VariableDeclaration.new(
- AST::Identifier.new('x'),
- AST::Number.new(1.0)
- )
- ]
- )
- end
-
- it 'parses function definition' do
- result = [
- AST::FunctionDefinition.new(
- AST::Identifier.new('add_one'),
- [AST::Identifier.new('x')],
- AST::Block.new(
- [
- AST::Binary.new(
- AST::Operators::ADD,
- AST::Identifier.new('x'),
- AST::Number.new(1.0)
- )
- ]
- )
- )
- ]
-
- expect(parse('function add_one(x) { x + 1; }')).to eq(result)
- expect(parse('function add_one(x,) { x + 1; }')).to eq(result)
- end
-
- it 'parses function call' do
- result = [
- AST::FunctionCall.new(
- AST::Identifier.new('func'),
- [AST::Number.new(1.0), AST::Number.new(2.0)]
- )
- ]
-
- expect(parse('func(1, 2);')).to eq(result)
- expect(parse('func(1, 2,);')).to eq(result)
- end
-
- it 'parses array literal' do
- result = [
- AST::Array.new(
- [AST::Number.new(1.0), AST::Number.new(2.0), AST::Number.new(3.0)]
- )
- ]
-
- expect(parse('[1, 2, 3];')).to eq(result)
- expect(parse('[1, 2, 3,];')).to eq(result)
- end
-
- it 'parses a class definition do' do
- expect(
- parse(<<~CLASS)
- class Class {
- public foo, bar;
- private baz;
- function method() {
- "method";
- }
- }
- CLASS
- ).to eq(
- [
- AST::ClassDefinition.new(
- AST::Identifier.new('Class'),
- [
- AST::Member.new(AST::Identifier.new('foo'), true),
- AST::Member.new(AST::Identifier.new('bar'), true),
- AST::Member.new(AST::Identifier.new('baz'), false)
- ],
- [
- AST::FunctionDefinition.new(
- AST::Identifier.new('method'),
- [],
- AST::Block.new([AST::String.new('method')])
- )
- ]
- )
- ]
- )
- end
-
- it 'gives function calls higher precedence than binary operations' do
- expect(parse('x + func(y);')).to eq(
- [
- AST::Binary.new(
- AST::Operators::ADD,
- AST::Identifier.new('x'),
- AST::FunctionCall.new(
- AST::Identifier.new('func'),
- [
- AST::Identifier.new('y'),
- ]
- )
- )
- ]
- )
- end
- end
|