gloss 0.0.3 → 0.1.1

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +3 -0
  3. data/.github/workflows/{crystal.yml → crystal_specs.yml} +1 -1
  4. data/.github/workflows/{ruby.yml → ruby_specs.yml} +2 -2
  5. data/.gloss.yml +1 -0
  6. data/.rspec +1 -0
  7. data/Gemfile.lock +10 -12
  8. data/README.md +36 -5
  9. data/Rakefile +1 -1
  10. data/exe/gloss +13 -2
  11. data/ext/gloss/Makefile +8 -19
  12. data/ext/gloss/{src/lib → lib}/cr_ruby.cr +0 -0
  13. data/ext/gloss/lib/rbs_types.cr +3 -0
  14. data/ext/gloss/spec/parser_spec.cr +83 -83
  15. data/ext/gloss/src/cr_ast.cr +96 -77
  16. data/ext/gloss/src/gloss.cr +2 -2
  17. data/ext/gloss/src/lexer.cr +59 -1
  18. data/ext/gloss/src/rb_ast.cr +114 -63
  19. data/lib/gloss.rb +15 -7
  20. data/lib/gloss/cli.rb +85 -28
  21. data/lib/gloss/config.rb +13 -7
  22. data/lib/gloss/errors.rb +3 -4
  23. data/lib/gloss/initializer.rb +9 -9
  24. data/lib/gloss/logger.rb +29 -0
  25. data/lib/gloss/parser.rb +19 -5
  26. data/lib/gloss/prog_loader.rb +141 -0
  27. data/lib/gloss/scope.rb +7 -2
  28. data/lib/gloss/source.rb +17 -14
  29. data/lib/gloss/type_checker.rb +86 -33
  30. data/lib/gloss/utils.rb +44 -0
  31. data/lib/gloss/version.rb +1 -2
  32. data/lib/gloss/visitor.rb +667 -0
  33. data/lib/gloss/watcher.rb +51 -16
  34. data/lib/gloss/writer.rb +24 -15
  35. data/sig/core.rbs +2 -0
  36. data/sig/fast_blank.rbs +4 -0
  37. data/sig/{gloss.rbs → gls.rbs} +0 -0
  38. data/sig/listen.rbs +1 -0
  39. data/sig/optparse.rbs +6 -0
  40. data/sig/rubygems.rbs +9 -0
  41. data/sig/yaml.rbs +3 -0
  42. data/src/exe/gloss +19 -0
  43. data/src/lib/gloss.gl +26 -0
  44. data/src/lib/gloss/cli.gl +70 -0
  45. data/src/lib/gloss/config.gl +9 -3
  46. data/src/lib/gloss/initializer.gl +4 -6
  47. data/src/lib/gloss/logger.gl +21 -0
  48. data/src/lib/gloss/parser.gl +17 -5
  49. data/src/lib/gloss/prog_loader.gl +133 -0
  50. data/src/lib/gloss/scope.gl +7 -0
  51. data/src/lib/gloss/source.gl +32 -0
  52. data/src/lib/gloss/type_checker.gl +85 -36
  53. data/src/lib/gloss/utils.gl +38 -0
  54. data/src/lib/gloss/version.gl +1 -1
  55. data/src/lib/gloss/visitor.gl +575 -0
  56. data/src/lib/gloss/watcher.gl +44 -10
  57. data/src/lib/gloss/writer.gl +16 -14
  58. metadata +28 -8
  59. data/lib/gloss/builder.rb +0 -447
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a1461d26e97ea9693ee00d63016e0fa1e34ea719de672ae0d4c303e4efb5144
4
- data.tar.gz: 2370827768056a2575c1987d661a140d7247b68629e049aa58b0bc9d1de0bc31
3
+ metadata.gz: 265e6f48bffa061f213e15f98be4d31b97c900701e95c381c1176048d9e8a75f
4
+ data.tar.gz: 9398669043cd6de339664f87529388f68d83f519d650b72ea06de6715d7477bb
5
5
  SHA512:
6
- metadata.gz: 17d5c598e8199b375599112a4365cb14691e651783a86880844dd35ff312dc2ca2ed0bb632e0a51897dcd3ba774231ae9c547710f19ed134318a39e098224a37
7
- data.tar.gz: 6626ff60cab24dacfc6e6780368a719e04c45c80c1f4e8b89db76bfdc0848f725e33d907058b6c9991fc80c1b97b518503eb42a47435c733f43a4e0d0d49eb0e
6
+ metadata.gz: d0ef0a2208f005eaa87c77fcc2e1cca5e2bdf4d08e712a70d0cf5dfa57e4a3d45a691dbc873f47d7c95a928ea48d36fa885b9ca2a62b52e55a42f7ae3540613d
7
+ data.tar.gz: a21377a395aa60bec26f0d420b8bb2124cb121994bf635b34653e290f0d2441f160888755695711ee6c1dd0e1e16da65fca9c6423a1b0f4600a7a15dc4b4a5a3
data/.gitattributes ADDED
@@ -0,0 +1,3 @@
1
+ lib/gloss/**/*.rb linguist-generated
2
+ # this will basically cover 99% of the syntax anyway
3
+ **/*.gl linguist-language=Crystal
@@ -1,4 +1,4 @@
1
- name: Crystal CI
1
+ name: Crystal Specs
2
2
 
3
3
  on:
4
4
  push:
@@ -5,7 +5,7 @@
5
5
  # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
6
  # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
7
 
8
- name: Ruby
8
+ name: Ruby Specs
9
9
 
10
10
  on:
11
11
  push:
@@ -16,7 +16,7 @@ on:
16
16
  jobs:
17
17
  test:
18
18
 
19
- runs-on: ubuntu-latest
19
+ runs-on: ubuntu-20.04
20
20
 
21
21
  steps:
22
22
  - uses: actions/checkout@v2
data/.gloss.yml CHANGED
@@ -1,3 +1,4 @@
1
1
  ---
2
2
  frozen_string_literals: true
3
3
  src_dir: src
4
+ entrypoint: src/exe/gloss
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gloss (0.0.3)
4
+ gloss (0.1.1)
5
5
  fast_blank
6
6
  listen
7
7
  rbs
@@ -17,16 +17,15 @@ GEM
17
17
  tzinfo (~> 2.0)
18
18
  zeitwerk (~> 2.3)
19
19
  ast (2.4.1)
20
- ast_utils (0.3.0)
21
- parser (~> 2.4)
22
- thor (>= 0.19)
20
+ ast_utils (0.4.0)
21
+ parser (>= 2.7.0)
23
22
  byebug (11.1.3)
24
23
  coderay (1.1.3)
25
- concurrent-ruby (1.1.7)
24
+ concurrent-ruby (1.1.8)
26
25
  diff-lcs (1.4.4)
27
26
  fast_blank (1.0.0)
28
27
  ffi (1.14.2)
29
- i18n (1.8.7)
28
+ i18n (1.8.8)
30
29
  concurrent-ruby (~> 1.0)
31
30
  language_server-protocol (3.15.0.1)
32
31
  listen (3.4.1)
@@ -50,7 +49,7 @@ GEM
50
49
  rb-fsevent (0.10.4)
51
50
  rb-inotify (0.10.1)
52
51
  ffi (~> 1.0)
53
- rbs (1.0.0)
52
+ rbs (1.0.4)
54
53
  regexp_parser (2.0.3)
55
54
  rexml (3.2.4)
56
55
  rspec (3.10.0)
@@ -78,15 +77,14 @@ GEM
78
77
  rubocop-ast (1.4.0)
79
78
  parser (>= 2.7.1.5)
80
79
  ruby-progressbar (1.11.0)
81
- steep (0.39.0)
80
+ steep (0.41.0)
82
81
  activesupport (>= 5.1)
83
- ast_utils (~> 0.3.0)
82
+ ast_utils (>= 0.4.0)
84
83
  language_server-protocol (~> 3.15.0.1)
85
84
  listen (~> 3.0)
86
- parser (~> 2.7.0)
85
+ parser (>= 2.7)
87
86
  rainbow (>= 2.2.2, < 4.0)
88
- rbs (~> 1.0.0)
89
- thor (1.0.1)
87
+ rbs (~> 1.0.3)
90
88
  tzinfo (2.0.4)
91
89
  concurrent-ruby (~> 1.0)
92
90
  unicode-display_width (1.7.0)
data/README.md CHANGED
@@ -1,7 +1,15 @@
1
1
  # Gloss
2
+ [![Gem Version](https://badge.fury.io/rb/gloss.svg)](https://rubygems.org/gems/gloss)
3
+ [![Ruby Specs](https://github.com/johansenja/gloss/workflows/Ruby%20Specs/badge.svg)](https://github.com/johansenja/gloss/actions?query=workflow%3A%22Ruby+Specs%22)
4
+ [![Crystal Specs](https://github.com/johansenja/gloss/workflows/Crystal%20Specs/badge.svg)](https://github.com/johansenja/gloss/actions?query=workflow%3A%22Crystal+Specs%22)
5
+ [![Total Downloads](http://ruby-gem-downloads-badge.herokuapp.com/gloss?type=total&color=green&metric=true&label=downloads%20(total)&total_label=)](https://rubygems.org/gems/gloss)
6
+ [![Current Version](http://ruby-gem-downloads-badge.herokuapp.com/gloss?color=green&label=downloads%20(current%20version)&metric=true)](https://rubygems.org/gems/gloss)
7
+ [![Total Views](https://counter.gofiber.io/badge/johansenja/gloss)](https://rubygems.org/gems/gloss)
2
8
 
3
9
  [Gloss](https://en.wikipedia.org/wiki/Gloss_(annotation)) is a high-level programming language based on [Ruby](https://github.com/ruby/ruby) and [Crystal](https://github.com/crystal-lang/crystal), which compiles to ruby; its aims are on transparency,
4
- efficiency, and to enhance ruby's goal of developer happiness and productivity. Some of the features include:
10
+ efficiency, and to enhance ruby's goal of developer happiness and productivity.
11
+
12
+ ### Current features
5
13
 
6
14
  - Type checking, via optional type annotations
7
15
  - Compile-time macros
@@ -10,11 +18,26 @@ efficiency, and to enhance ruby's goal of developer happiness and productivity.
10
18
  - All ruby files are valid gloss files (a small exceptions for now; workarounds are mostly available)
11
19
  - Other syntactic sugar
12
20
 
13
- Coming soon:
14
- - abstract classes
21
+ ### Current Status
22
+
23
+ This project is at a stage where the core non-crystal parts are written in Gloss and compile to ruby (essentially self-hosting), albeit with the type checking being fairly loose. However the project is still in the very early stages; with (as of yet) no Linux support nor error handling (see roadmap below). Use at your own discretion!
24
+
25
+ ### Approx. roadmap:
26
+
27
+ - Improve error handling and logging (currently almost non-existant)
28
+ - Address Linux compatibility (currently more or less non-existant)
29
+ - Implement different strictnesses of type checking
30
+ - Metaprogramming helpers/safety:*
31
+ - Abstract classes and methods
32
+ - Method lookup/existence checking at compile time
33
+ - Method overloading
34
+
35
+ #### Related items:
36
+
37
+ - Rails helpers; probably some time away*
38
+ - Editor plugins/syntax highlighting/langserver; probably some time away*
15
39
 
16
- Maybe on the roadmap:
17
- - Method overloading
40
+ *__Dependent on popularity__
18
41
 
19
42
  ## Examples:
20
43
 
@@ -223,4 +246,12 @@ then
223
246
 
224
247
  then
225
248
 
249
+ `mkdir src && echo "puts 'hello world'" > src/hello_world.gl`
250
+
251
+ then
252
+
226
253
  `gloss build`
254
+
255
+ then
256
+
257
+ `ruby ./hello_world.rb`
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ RSpec::Core::RakeTask.new :spec do |spec|
18
18
  end
19
19
 
20
20
  task :build do
21
- `cd ext/gloss && make && cd -`
21
+ sh "cd", "ext/gloss", "&&", "make", "all", "&&", "cd", "-"
22
22
  end
23
23
 
24
24
  task :default => [:spec]
data/exe/gloss CHANGED
@@ -1,6 +1,17 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ ##### This file was generated by Gloss; any changes made here will be overwritten.
5
+ ##### See src/ to make changes
2
6
 
3
7
  require "bundler/setup"
4
8
  require "gloss"
5
-
6
- Gloss::CLI.new(ARGV).run
9
+ begin
10
+ Gloss::CLI.new(ARGV)
11
+ .run
12
+ rescue SystemExit
13
+ rescue => e
14
+ abort(" Unexpected error: #{e.class
15
+ .name}\n Message: #{e.message}\n Trace:\n #{e.backtrace
16
+ .join("\n")}\n\n This is probably a bug and may warrant a bug report at https://github.com/johansenja/gloss/issues")
17
+ end
data/ext/gloss/Makefile CHANGED
@@ -1,26 +1,20 @@
1
1
  CRYSTAL = crystal
2
- TARGET = ../../lib/gls
3
-
4
2
  PLATFORM = $(shell uname -s)
5
3
 
6
4
  ifeq "$(PLATFORM)" "Darwin"
7
- install: all
8
-
9
- all: clean shards build
5
+ TARGET = ../../lib/gls.bundle
10
6
 
11
- shards:
12
- shards
7
+ clean:
8
+ rm -f $(TARGET) $(TARGET).dwarf
9
+ endif
13
10
 
14
- build: ./src/gloss.cr
15
- $(CRYSTAL) build --link-flags "-dynamic -bundle -Wl,-undefined,dynamic_lookup" $< -o $(TARGET).bundle
11
+ ifeq "$(PLATFORM)" "Linux"
12
+ TARGET = ../../lib/gls.so
16
13
 
17
14
  clean:
18
- rm -f $(TARGET).bundle
19
- rm -f $(TARGET).bundle.dwarf
15
+ rm -f $(TARGET)
20
16
  endif
21
17
 
22
- ifeq "$(PLATFORM)" "Linux"
23
- LLVM_TARGET = "$(shell uname -m)-unknown-linux-gnu"
24
18
  install: all
25
19
 
26
20
  all: clean shards build
@@ -29,9 +23,4 @@ shards:
29
23
  shards
30
24
 
31
25
  build: ./src/gloss.cr
32
- $(CRYSTAL) build $< --cross-compile --target $(LLVM_TARGET) --link-flags "-dynamic -bundle -Wl,-undefined,dynamic_lookup" -o $(TARGET)
33
-
34
- clean:
35
- rm -f $(TARGET).o
36
- rm -f $(TARGET).so
37
- endif
26
+ $(CRYSTAL) build --link-flags "-shared -dynamic -Wl,-undefined,dynamic_lookup" $< -o $(TARGET) --release
File without changes
@@ -0,0 +1,3 @@
1
+ module Gloss
2
+ class Any; end
3
+ end
@@ -16,13 +16,13 @@ module Gloss
16
16
  Gloss.parse_string("hsh = {}").should be_truthy
17
17
  end
18
18
 
19
- it "parses all kinds of method args" do
20
- output = %q|{"type":"DefNode","name":"abc","body":null,"rp_args":[{"type":"Arg","name":"a","external_name":"a","default_value":null,"restriction":{"type":"Path","value":"Float"},"keyword_arg":false},{"type":"Arg","name":"b","external_name":"b","default_value":null,"restriction":null,"keyword_arg":false},{"type":"Arg","name":"c","external_name":"c","default_value":null,"restriction":null,"keyword_arg":false,splat: "true"},{"type":"Arg","name":"d","external_name":"d","default_value":{"type":"LiteralNode","value":"nil","rb_type":"NilClass"},"restriction":{"type":"Union","types":[{"type":"Path","value":"String"},{"type":"Path","value":"Nil"}]},"keyword_arg":false},{"type":"Arg","name":"e","external_name":"e","default_value":null,"restriction":{"type":"Path","value":"Integer"},"keyword_arg":true},{"type":"Arg","name":"f","external_name":"f","default_value":null,"restriction":null,"keyword_arg":true},{"type":"Arg","name":"g","external_name":"g","default_value":{"type":"LiteralNode","value":"nil","rb_type":"NilClass"},"restriction":{"type":"Path","value":"String"},"keyword_arg":true}],"receiver":null,"return_type":null,"rest_kw_args":{"type":"Arg","name":"h","external_name":"h","default_value":null,"restriction":null,"keyword_arg":false}}|
21
- Gloss.parse_string(<<-GLS).should eq output
22
- def abc(a : Float, b, *c, d : String? = nil, e: : Integer, f:, g: : String = nil, **h)
23
- end
24
- GLS
25
- end
19
+ # it "parses all kinds of method args" do
20
+ # output = %q|{"type":"DefNode","name":"abc","body":null,"rp_args":[{"type":"Arg","name":"a","external_name":"a","default_value":null,"restriction":{"type":"Path","value":"Float"},"keyword_arg":false},{"type":"Arg","name":"b","external_name":"b","default_value":null,"restriction":null,"keyword_arg":false},{"type":"Arg","name":"c","external_name":"c","default_value":null,"restriction":null,"keyword_arg":false,splat: "true"},{"type":"Arg","name":"d","external_name":"d","default_value":{"type":"LiteralNode","value":"nil","rb_type":"NilClass"},"restriction":{"type":"Union","types":[{"type":"Path","value":"String"},{"type":"Path","value":"Nil"}]},"keyword_arg":false},{"type":"Arg","name":"e","external_name":"e","default_value":null,"restriction":{"type":"Path","value":"Integer"},"keyword_arg":true},{"type":"Arg","name":"f","external_name":"f","default_value":null,"restriction":null,"keyword_arg":true},{"type":"Arg","name":"g","external_name":"g","default_value":{"type":"LiteralNode","value":"nil","rb_type":"NilClass"},"restriction":{"type":"Path","value":"String"},"keyword_arg":true}],"receiver":null,"return_type":null,"rest_kw_args":{"type":"Arg","name":"h","external_name":"h","default_value":null,"restriction":null,"keyword_arg":false}}|
21
+ # Gloss.parse_string(<<-GLS).should eq output
22
+ # def abc(a : Float, b, *c, d : String? = nil, e: : Integer, f:, g: : String = nil, **h)
23
+ # end
24
+ # GLS
25
+ # end
26
26
 
27
27
  it "parses rescue with ruby syntax" do
28
28
  Gloss.parse_string(<<-GLOSS).should be_truthy
@@ -35,90 +35,90 @@ module Gloss
35
35
  end
36
36
  GLOSS
37
37
  end
38
- end
39
-
40
- it "parses shorthand blocks with ruby syntax" do
41
- Gloss.parse_string("[1].map(&:to_s)").should eq(
42
- %q<{"type":"Call","name":"map","args":[],"object":{"type":"ArrayLiteral","elements":[{"type":"LiteralNode","value":"1","rb_type":"Integer"}],"frozen":false},"block":null,"block_arg":{"type":"LiteralNode","value":":to_s","rb_type":"Symbol"}}>
43
- )
44
- end
45
-
46
- it "parses tuples as frozen arrays" do
47
- Gloss.parse_string("{ 'hello', 'world' }").should eq(
48
- %q<{"type":"ArrayLiteral","elements":[{"type":"LiteralNode","value":"\"hello\"","rb_type":"String"},{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}],"frozen":true}>
49
- )
50
- end
51
38
 
52
- it "parses named tuples as frozen hashes" do
53
- Gloss.parse_string("{ hello: 'world' }").should eq(
54
- %q<{"type":"HashLiteral","elements":[["hello",{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}]],"frozen":true}>
55
- )
56
- end
57
-
58
- it "parses the and operator" do
59
- Gloss.parse_string("puts 'hello world' if 1 and 2").should be_truthy
60
- end
61
-
62
- it "parses the or operator" do
63
- Gloss.parse_string("puts 'hello world' if true or false").should be_truthy
64
- end
65
-
66
- it "parses the not operator" do
67
- Gloss.parse_string("puts 'hello world' if true and not false").should be_truthy
68
- end
39
+ # it "parses shorthand blocks with ruby syntax" do
40
+ # Gloss.parse_string("[1].map(&:to_s)").should eq(
41
+ # %q<{"type":"Call","name":"map","args":[],"object":{"type":"ArrayLiteral","elements":[{"type":"LiteralNode","value":"1","rb_type":"Integer"}],"frozen":false},"block":null,"block_arg":{"type":"LiteralNode","value":":to_s","rb_type":"Symbol"}}>
42
+ # )
43
+ # end
69
44
 
70
- it "parses global variables" do
71
- Gloss.parse_string("$var : String = 'hello world'").should eq(
72
- %q|{"type":"TypeDeclaration","var":{"type":"GlobalVar","name":"$var"},"declared_type":{"type":"Path","value":"String"},"value":{"type":"LiteralNode","value":"\"hello world\"","rb_type":"String"},"var_type":"GlobalVar"}|
73
- )
74
- end
75
-
76
- it "parses for loops" do
77
- Gloss.parse_string(<<-GLS).should be_truthy
78
- for k, v in { hello: world }
79
- puts key: k, value: v
80
- end
81
- GLS
82
- end
45
+ it "parses tuples as frozen arrays" do
46
+ Gloss.parse_string("{ 'hello', 'world' }").should eq(
47
+ %q<{"type":"ArrayLiteral","elements":[{"type":"LiteralNode","value":"\"hello\"","rb_type":"String"},{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}],"frozen":true}>
48
+ )
49
+ end
83
50
 
84
- it "parses generics as RBS generics" do
85
- expected =
86
- %q|{"type":"TypeDeclaration","var":{"type":"Var","name":"hsh"},"declared_type":{"type":"Generic","name":{"type":"Path","value":"Hash"},"args":[{"type":"Path","value":"String"},{"type":"Path","value":"String"}]},"value":{"type":"HashLiteral","elements":[[{"type":"LiteralNode","value":"\"hello\"","rb_type":"String"},{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}]],"frozen":false},"var_type":"Var"}|
87
- Gloss.parse_string(<<-GLS).should eq expected
88
- hsh : Hash[String, String] = { "hello" => "world" }
89
- GLS
90
- end
51
+ it "parses named tuples as frozen hashes" do
52
+ Gloss.parse_string("{ hello: 'world' }").should eq(
53
+ %q<{"type":"HashLiteral","elements":[["hello",{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}]],"frozen":true}>
54
+ )
55
+ end
91
56
 
92
- it "parses method calls in case statements" do
93
- expected =
94
- %q|{"type":"Case","condition":{"type":"LiteralNode","value":"\"abc\"","rb_type":"String"},"whens":[{"type":"When","conditions":[{"type":"Proc","function":{"type":"DefNode","name":"->","body":{"type":"Call","name":"start_with?","args":[{"type":"LiteralNode","value":"\"a\"","rb_type":"String"}],"object":{"type":"Var","name":"x"},"block":null,"block_arg":null},"rp_args":[{"type":"Arg","name":"x","external_name":"x","default_value":null,"restriction":null,"keyword_arg":false}],"receiver":null,"return_type":null,"rest_kw_args":null}}],"body":{"type":"LiteralNode","value":"1","rb_type":"Integer"},"exhaustive":false}],"else":{"type":"LiteralNode","value":"0","rb_type":"Integer"},"exhaustive":false}|
95
- Gloss.parse_string(<<-GLS).should eq expected
96
- case "abc"
97
- when .start_with? 'a'
98
- 1
99
- else
100
- 0
101
- end
102
- GLS
103
- end
57
+ # it "parses the and operator" do
58
+ # Gloss.parse_string("puts 'hello world' if 1 and 2").should be_truthy
59
+ # end
104
60
 
105
- it "allows constant methods" do
106
- Gloss.parse_string(<<-GLS).should be_truthy
107
- def Hello(arg = nil)
108
- end
61
+ # it "parses the or operator" do
62
+ # Gloss.parse_string("puts 'hello world' if true or false").should be_truthy
63
+ # end
109
64
 
110
- Hello()
65
+ # it "parses the not operator" do
66
+ # Gloss.parse_string("puts 'hello world' if true and not false").should be_truthy
67
+ # end
111
68
 
112
- Hello("a")
113
- GLS
114
- end
69
+ it "parses global variables" do
70
+ Gloss.parse_string("$var : String = 'hello world'").should eq(
71
+ %q|{"type":"TypeDeclaration","var":{"type":"GlobalVar","name":"$var"},"declared_type":{"type":"Path","value":"String"},"value":{"type":"LiteralNode","value":"\"hello world\"","rb_type":"String"},"var_type":"GlobalVar"}|
72
+ )
73
+ end
115
74
 
116
- it "requires constant methods to be called with ()" do
117
- Gloss.parse_string(<<-GLS).should be_falsey
118
- def Hello(arg = nil)
119
- end
75
+ # it "parses for loops" do
76
+ # Gloss.parse_string(<<-GLS).should be_truthy
77
+ # for k, v in { hello: world }
78
+ # puts key: k, value: v
79
+ # end
80
+ # GLS
81
+ # end
82
+
83
+ it "parses generics as RBS generics" do
84
+ expected =
85
+ %q|{"type":"TypeDeclaration","var":{"type":"Var","name":"hsh"},"declared_type":{"type":"Generic","name":{"type":"Path","value":"Hash"},"args":[{"type":"Path","value":"String"},{"type":"Path","value":"String"}]},"value":{"type":"HashLiteral","elements":[[{"type":"LiteralNode","value":"\"hello\"","rb_type":"String"},{"type":"LiteralNode","value":"\"world\"","rb_type":"String"}]],"frozen":false},"var_type":"Var"}|
86
+ Gloss.parse_string(<<-GLS).should eq expected
87
+ hsh : Hash[String, String] = { "hello" => "world" }
88
+ GLS
89
+ end
120
90
 
121
- Hello
122
- GLS
91
+ # it "parses method calls in case statements" do
92
+ # expected =
93
+ # %q|{"type":"Case","condition":{"type":"LiteralNode","value":"\"abc\"","rb_type":"String"},"whens":[{"type":"When","conditions":[{"type":"Proc","function":{"type":"DefNode","name":"->","body":{"type":"Call","name":"start_with?","args":[{"type":"LiteralNode","value":"\"a\"","rb_type":"String"}],"object":{"type":"Var","name":"x"},"block":null,"block_arg":null},"rp_args":[{"type":"Arg","name":"x","external_name":"x","default_value":null,"restriction":null,"keyword_arg":false}],"receiver":null,"return_type":null,"rest_kw_args":null}}],"body":{"type":"LiteralNode","value":"1","rb_type":"Integer"},"exhaustive":false}],"else":{"type":"LiteralNode","value":"0","rb_type":"Integer"},"exhaustive":false}|
94
+ # Gloss.parse_string(<<-GLS).should eq expected
95
+ # case "abc"
96
+ # when .start_with? 'a'
97
+ # 1
98
+ # else
99
+ # 0
100
+ # end
101
+ # GLS
102
+ # end
103
+
104
+ # it "allows constant methods" do
105
+ # Gloss.parse_string(<<-GLS).should be_truthy
106
+ # def Hello(arg = nil)
107
+ # end
108
+
109
+ # Hello()
110
+
111
+ # Hello("a")
112
+ # GLS
113
+ # end
114
+
115
+ # it "requires constant methods to be called with ()" do
116
+ # Gloss.parse_string(<<-GLS).should be_falsey
117
+ # def Hello(arg = nil)
118
+ # end
119
+
120
+ # Hello
121
+ # GLS
122
+ # end
123
123
  end
124
124
  end
@@ -5,7 +5,7 @@ require "./rb_ast"
5
5
  module Crystal
6
6
  abstract class ASTNode
7
7
  def to_rb
8
- Rb::AST::EmptyNode.new(self.class.name)
8
+ Rb::AST::EmptyNode.new(self.class.name, @location)
9
9
  end
10
10
  end
11
11
 
@@ -17,13 +17,13 @@ module Crystal
17
17
 
18
18
  class Expressions < ASTNode
19
19
  def to_rb
20
- Rb::AST::CollectionNode.new(@expressions.map(&.to_rb))
20
+ Rb::AST::CollectionNode.new(@expressions.map(&.to_rb), @location)
21
21
  end
22
22
  end
23
23
 
24
24
  class NilLiteral < ASTNode
25
25
  def to_rb
26
- Rb::AST::LiteralNode.new("nil", Rb::AST::RbLiteral::NilClass)
26
+ Rb::AST::LiteralNode.new("nil", Rb::AST::RbLiteral::NilClass, @location)
27
27
  end
28
28
  end
29
29
 
@@ -31,105 +31,116 @@ module Crystal
31
31
  def to_rb
32
32
  Rb::AST::LiteralNode.new(
33
33
  @value.inspect,
34
- @value ? Rb::AST::RbLiteral::TrueClass : Rb::AST::RbLiteral::FalseClass
35
- )
34
+ @value ? Rb::AST::RbLiteral::TrueClass : Rb::AST::RbLiteral::FalseClass, @location)
36
35
  end
37
36
  end
38
37
 
39
38
  class NumberLiteral < ASTNode
40
39
  def to_rb
41
- Rb::AST::LiteralNode.new(@value, Rb::AST::RbLiteral::Integer)
40
+ Rb::AST::LiteralNode.new(@value, Rb::AST::RbLiteral::Integer, @location)
42
41
  end
43
42
  end
44
43
 
45
44
  class CharLiteral < ASTNode
46
45
  def to_rb
47
- Rb::AST::LiteralNode.new(@value.inspect, Rb::AST::RbLiteral::String)
46
+ Rb::AST::LiteralNode.new(@value.inspect, Rb::AST::RbLiteral::String, @location)
48
47
  end
49
48
  end
50
49
 
51
50
  class StringLiteral < ASTNode
52
51
  def to_rb
53
- Rb::AST::LiteralNode.new(@value.inspect, Rb::AST::RbLiteral::String)
52
+ Rb::AST::LiteralNode.new(@value.inspect, Rb::AST::RbLiteral::String, @location)
54
53
  end
55
54
  end
56
55
 
57
56
  class StringInterpolation < ASTNode
58
57
  def to_rb
59
- Rb::AST::StringInterpolation.new(@expressions.map &.to_rb)
58
+ Rb::AST::StringInterpolation.new(@expressions.map &.to_rb, @location)
60
59
  end
61
60
  end
62
61
 
63
62
  class SymbolLiteral < ASTNode
64
63
  def to_rb
65
- Rb::AST::LiteralNode.new(%{:"#{@value.to_s}"}, Rb::AST::RbLiteral::Symbol)
64
+ Rb::AST::LiteralNode.new(%{:"#{@value.to_s}"}, Rb::AST::RbLiteral::Symbol, @location)
66
65
  end
67
66
  end
68
67
 
69
68
  class ArrayLiteral < ASTNode
70
69
  def to_rb
71
- Rb::AST::ArrayLiteral.new(@elements.map(&.to_rb))
70
+ Rb::AST::ArrayLiteral.new(@elements.map(&.to_rb), @location)
72
71
  end
73
72
  end
74
73
 
75
74
  class HashLiteral < ASTNode
76
75
  def to_rb
77
- Rb::AST::HashLiteral.new(@entries.map { |e| {e.key.to_rb, e.value.to_rb} })
76
+ Rb::AST::HashLiteral.new(@entries.map { |e| {e.key.to_rb, e.value.to_rb} }, @location)
78
77
  end
79
78
  end
80
79
 
81
80
  class NamedTupleLiteral < ASTNode
82
81
  def to_rb
83
- Rb::AST::HashLiteral.new(@entries.map { |e| {e.key, e.value.to_rb} }, frozen: true)
82
+ Rb::AST::HashLiteral.new(@entries.map { |e| {e.key, e.value.to_rb} }, @location, frozen: true)
84
83
  end
85
84
  end
86
85
 
87
86
  class RangeLiteral < ASTNode
88
87
  def to_rb
89
- Rb::AST::RangeLiteral.new(@from.to_rb, @to.to_rb, @exclusive)
88
+ Rb::AST::RangeLiteral.new(@from.to_rb, @to.to_rb, @exclusive, @location)
90
89
  end
91
90
  end
92
91
 
93
92
  class RegexLiteral < ASTNode
94
93
  def to_rb
95
- Rb::AST::RegexLiteral.new(@value.to_rb)
94
+ Rb::AST::RegexLiteral.new(@value.to_rb, @location)
96
95
  end
97
96
  end
98
97
 
99
98
  class TupleLiteral < ASTNode
100
99
  def to_rb
101
- Rb::AST::ArrayLiteral.new(@elements.map(&.to_rb), frozen: true)
100
+ Rb::AST::ArrayLiteral.new(@elements.map(&.to_rb), @location, frozen: true)
102
101
  end
103
102
  end
104
103
 
105
104
  class Def < ASTNode
106
105
  def to_rb
107
- Rb::AST::DefNode.new(@name, @args.map(&.to_rb), @body.to_rb, receiver.try(&.to_rb),
108
- return_type.try(&.to_rb), @double_splat.try(&.to_rb))
106
+ positional_args = args.dup
107
+ splat = @splat_index ? positional_args.delete_at(@splat_index.as(Int32)) : nil
108
+ Rb::AST::DefNode.new(
109
+ receiver.try(&.to_rb),
110
+ @name,
111
+ positional_args.map(&.to_rb),
112
+ splat.try(&.to_rb),
113
+ @double_splat.try(&.to_rb),
114
+ @body.to_rb,
115
+ return_type.try(&.to_rb),
116
+ @yields,
117
+ @block_arg.try &.to_rb, @location)
109
118
  end
110
119
  end
111
120
 
112
121
  class ClassDef < ASTNode
113
122
  def to_rb
114
- Rb::AST::ClassNode.new(@name.to_rb, @body.to_rb, @superclass.try(&.to_rb), @type_vars, @abstract)
123
+ Rb::AST::ClassNode.new(@name.to_rb, @body.to_rb, @superclass.try(&.to_rb), @type_vars, @abstract, @location)
115
124
  end
116
125
  end
117
126
 
118
127
  class ModuleDef < ASTNode
119
128
  def to_rb
120
- Rb::AST::ModuleNode.new(@name.to_rb, @body.to_rb, @type_vars)
129
+ Rb::AST::ModuleNode.new(@name.to_rb, @body.to_rb, @type_vars, @location)
121
130
  end
122
131
  end
123
132
 
124
133
  class Var < ASTNode
125
134
  def to_rb
126
- Rb::AST::Var.new(@name)
135
+ Rb::AST::Var.new(@name, @location)
127
136
  end
128
137
  end
129
138
 
130
139
  class Block < ASTNode
131
140
  def to_rb
132
- Rb::AST::Block.new(@args.map(&.to_rb), @body.to_rb)
141
+ positional_args = args.dup
142
+ splat = @splat_index ? positional_args.delete_at(@splat_index.as(Int32)) : nil
143
+ Rb::AST::Block.new(positional_args.map(&.to_rb), splat.try &.to_rb, @body.to_rb, @location)
133
144
  end
134
145
  end
135
146
 
@@ -141,8 +152,8 @@ module Crystal
141
152
  @args.map(&.to_rb),
142
153
  @named_args.try(&.map(&.to_rb.as(Rb::AST::Arg))),
143
154
  @block.try(&.to_rb),
144
- @block_arg.try(&.to_rb)
145
- )
155
+ @block_arg.try(&.to_rb),
156
+ @has_parentheses, @location)
146
157
  end
147
158
  end
148
159
 
@@ -151,127 +162,121 @@ module Crystal
151
162
 
152
163
  def to_rb
153
164
  Rb::AST::Arg.new(@name, @external_name, @restriction.try(&.to_rb),
154
- @default_value.try(&.to_rb), @keyword_arg)
165
+ @default_value.try(&.to_rb), @keyword_arg, @location)
155
166
  end
156
167
  end
157
168
 
158
169
  class NamedArgument < ASTNode
159
170
  def to_rb
160
- Rb::AST::Arg.new(@name, @name, nil, @value.to_rb, true)
171
+ Rb::AST::Arg.new(@name, @name, nil, @value.to_rb, true, @location)
161
172
  end
162
173
  end
163
174
 
164
175
  class If < ASTNode
165
176
  def to_rb
166
- Rb::AST::If.new(@cond.to_rb, @then.to_rb, @else.to_rb)
177
+ Rb::AST::If.new(@cond.to_rb, @then.to_rb, @else.to_rb, @location)
167
178
  end
168
179
  end
169
180
 
170
181
  class Unless < ASTNode
171
182
  def to_rb
172
- Rb::AST::Unless.new(@cond.to_rb, @then.to_rb, @else.to_rb)
183
+ Rb::AST::Unless.new(@cond.to_rb, @then.to_rb, @else.to_rb, @location)
173
184
  end
174
185
  end
175
186
 
176
187
  class Assign < ASTNode
177
188
  def to_rb
178
- Rb::AST::Assign.new(@target.to_rb, @value.to_rb)
189
+ Rb::AST::Assign.new(@target.to_rb, @value.to_rb, nil, @location)
179
190
  end
180
191
  end
181
192
 
182
193
  class OpAssign < ASTNode
183
194
  def to_rb
184
- Rb::AST::Assign.new(@target.to_rb, @value.to_rb, @op)
195
+ Rb::AST::Assign.new(@target.to_rb, @value.to_rb, @op, @location)
185
196
  end
186
197
  end
187
198
 
188
199
  class MultiAssign < ASTNode
189
200
  def to_rb
190
- Rb::AST::EmptyNode.new(self.class.name)
201
+ Rb::AST::MultiAssign.new(@targets.map(&.to_rb), @values.map(&.to_rb), @location)
191
202
  end
192
203
  end
193
204
 
194
205
  class InstanceVar < ASTNode
195
206
  def to_rb
196
- Rb::AST::InstanceVar.new(@name)
207
+ Rb::AST::InstanceVar.new(@name, @location)
197
208
  end
198
209
  end
199
210
 
200
211
  class ReadInstanceVar < ASTNode
201
212
  def to_rb
202
- Rb::AST::EmptyNode.new(self.class.name)
213
+ Rb::AST::EmptyNode.new(self.class.name, @location)
203
214
  end
204
215
  end
205
216
 
206
217
  class ClassVar < ASTNode
207
218
  def to_rb
208
- Rb::AST::EmptyNode.new(self.class.name)
219
+ Rb::AST::EmptyNode.new(self.class.name, @location)
209
220
  end
210
221
  end
211
222
 
212
223
  class Global < ASTNode
213
224
  def to_rb
214
- Rb::AST::GlobalVar.new(@name)
225
+ Rb::AST::GlobalVar.new(@name, @location)
215
226
  end
216
227
  end
217
228
 
218
229
  class Annotation < ASTNode
219
230
  def to_rb
220
- Rb::AST::EmptyNode.new(self.class.name)
221
- end
222
- end
223
-
224
- class MacroExpression < ASTNode
225
- def to_rb
226
- Rb::AST::EmptyNode.new(self.class.name)
231
+ Rb::AST::EmptyNode.new(self.class.name, @location)
227
232
  end
228
233
  end
229
234
 
230
235
  class MacroIf < ASTNode
231
236
  def to_rb
232
- Rb::AST::MacroIf.new(@cond.to_rb, @then.to_rb, @else.to_rb)
237
+ Rb::AST::MacroIf.new(@cond.to_rb, @then.to_rb, @else.to_rb, @location)
233
238
  end
234
239
  end
235
240
 
236
241
  class MacroFor < ASTNode
237
242
  def to_rb
238
- Rb::AST::MacroFor.new(@vars.map(&.to_rb), @exp.to_rb, @body.to_rb)
243
+ Rb::AST::MacroFor.new(@vars.map(&.to_rb), @exp.to_rb, @body.to_rb, @location)
239
244
  end
240
245
  end
241
246
 
242
247
  class MacroVar < ASTNode
243
248
  def to_rb
244
- Rb::AST::EmptyNode.new(self.class.name)
249
+ Rb::AST::EmptyNode.new(self.class.name, @location)
245
250
  end
246
251
  end
247
252
 
248
253
  class MacroExpression < ASTNode
249
254
  def to_rb
250
- Rb::AST::MacroExpression.new(@exp.to_rb, @output)
255
+ Rb::AST::MacroExpression.new(@exp.to_rb, @output, @location)
251
256
  end
252
257
  end
253
258
 
254
259
  class MacroLiteral < ASTNode
255
260
  def to_rb
256
- Rb::AST::MacroLiteral.new(@value)
261
+ Rb::AST::MacroLiteral.new(@value, @location)
257
262
  end
258
263
  end
259
264
 
260
265
  class Annotation < ASTNode
261
266
  def to_rb
262
- Rb::AST::EmptyNode.new(self.class.name)
267
+ Rb::AST::EmptyNode.new(self.class.name, @location)
263
268
  end
264
269
  end
265
270
 
266
271
  class EnumDef < ASTNode
267
272
  def to_rb
268
- Rb::AST::Enum.new(@name, @members.map(&.to_rb))
273
+ Rb::AST::Enum.new(@name, @members.map(&.to_rb), @location)
269
274
  end
270
275
  end
271
276
 
272
277
  class Path < ASTNode
273
278
  def to_rb
274
- Rb::AST::Path.new(full_name)
279
+ Rb::AST::Path.new(full_name, @location)
275
280
  end
276
281
 
277
282
  def full_name
@@ -283,13 +288,13 @@ module Crystal
283
288
 
284
289
  class Require < ASTNode
285
290
  def to_rb
286
- Rb::AST::Require.new(@string)
291
+ Rb::AST::Require.new(@string, @location)
287
292
  end
288
293
  end
289
294
 
290
295
  class TypeDeclaration < ASTNode
291
296
  def to_rb
292
- Rb::AST::TypeDeclaration.new(@var.to_rb, @declared_type.to_rb, @value.try(&.to_rb))
297
+ Rb::AST::TypeDeclaration.new(@var.to_rb, @declared_type.to_rb, @value.try(&.to_rb), @location)
293
298
  end
294
299
  end
295
300
 
@@ -299,8 +304,7 @@ module Crystal
299
304
  @cond.try(&.to_rb),
300
305
  @whens.map(&.to_rb),
301
306
  @else.try(&.to_rb),
302
- @exhaustive
303
- )
307
+ @exhaustive, @location)
304
308
  end
305
309
  end
306
310
 
@@ -314,16 +318,14 @@ module Crystal
314
318
  Def.new(
315
319
  "->",
316
320
  [Arg.new(arg_name)],
317
- c.tap { |call| call.obj = Var.new(arg_name) }
318
- )
321
+ c.tap { |call| call.obj = Var.new(arg_name) })
319
322
  ).to_rb
320
323
  else
321
324
  c.to_rb
322
325
  end
323
326
  end,
324
327
  @body.to_rb,
325
- @exhaustive
326
- )
328
+ @exhaustive, @location)
327
329
  end
328
330
  end
329
331
 
@@ -343,8 +345,7 @@ module Crystal
343
345
  Rb::AST::UnaryExpr.new(
344
346
  @exp.to_rb,
345
347
  op,
346
- requires_parentheses
347
- )
348
+ requires_parentheses ,@location)
348
349
  end
349
350
  end
350
351
  {% end %}
@@ -359,8 +360,7 @@ module Crystal
359
360
  "||",
360
361
  {% end %}
361
362
  @left.to_rb,
362
- @right.to_rb
363
- )
363
+ @right.to_rb ,@location)
364
364
  end
365
365
  end
366
366
  {% end %}
@@ -368,7 +368,7 @@ module Crystal
368
368
  {% for class_name in %w[Return Break Next] %}
369
369
  class {{class_name.id}} < ControlExpression
370
370
  def to_rb
371
- Rb::AST::{{class_name.id}}.new(@exp.try(&.to_rb))
371
+ Rb::AST::{{class_name.id}}.new(@exp.try(&.to_rb),@location)
372
372
  end
373
373
  end
374
374
  {% end %}
@@ -376,43 +376,43 @@ module Crystal
376
376
  class ExceptionHandler < ASTNode
377
377
  def to_rb
378
378
  Rb::AST::ExceptionHandler.new(@body.to_rb, @rescues.try(&.map(&.to_rb)), @else.try(&.to_rb),
379
- @ensure.try(&.to_rb))
379
+ @ensure.try(&.to_rb), @location)
380
380
  end
381
381
  end
382
382
 
383
383
  class Rescue < ASTNode
384
384
  def to_rb
385
- Rb::AST::Rescue.new(@body.to_rb, @types.try(&.map(&.to_rb)), @name)
385
+ Rb::AST::Rescue.new(@body.to_rb, @types.try(&.map(&.to_rb)), @name, @location)
386
386
  end
387
387
  end
388
388
 
389
389
  class Union < ASTNode
390
390
  def to_rb
391
- Rb::AST::Union.new(@types.map(&.to_rb))
391
+ Rb::AST::Union.new(@types.map(&.to_rb), @location)
392
392
  end
393
393
  end
394
394
 
395
395
  class Generic < ASTNode
396
396
  def to_rb
397
- Rb::AST::Generic.new(@name.to_rb, @type_vars.map(&.to_rb))
397
+ Rb::AST::Generic.new(@name.to_rb, @type_vars.map(&.to_rb), @location)
398
398
  end
399
399
  end
400
400
 
401
401
  class ProcLiteral < ASTNode
402
402
  def to_rb
403
- Rb::AST::Proc.new(@def.to_rb)
403
+ Rb::AST::Proc.new(@def.to_rb, @location)
404
404
  end
405
405
  end
406
406
 
407
407
  class Include < ASTNode
408
408
  def to_rb
409
- Rb::AST::Include.new(@name.to_rb)
409
+ Rb::AST::Include.new(@name.to_rb, @location)
410
410
  end
411
411
  end
412
412
 
413
413
  class Extend < ASTNode
414
414
  def to_rb
415
- Rb::AST::Extend.new(@name.to_rb)
415
+ Rb::AST::Extend.new(@name.to_rb, @location)
416
416
  end
417
417
  end
418
418
 
@@ -424,27 +424,46 @@ module Crystal
424
424
  [@const.to_rb],
425
425
  nil,
426
426
  nil,
427
- nil
428
- )
427
+ nil,
428
+ false, @location)
429
+ end
430
+ end
431
+
432
+ class VisibilityModifier < ASTNode
433
+ def to_rb
434
+ Rb::AST::VisibilityModifier.new(@modifier, @exp.to_rb, @location)
435
+ end
436
+ end
437
+
438
+ class Yield < ASTNode
439
+ def to_rb
440
+ Rb::AST::Call.new(
441
+ nil,
442
+ "yield",
443
+ @exps.map(&.to_rb),
444
+ nil,
445
+ nil,
446
+ nil,
447
+ !@exps.empty?, @location)
429
448
  end
430
449
  end
431
450
 
432
- {% for class_name in %w[ProcNotation Macro OffsetOf VisibilityModifier RespondsTo
451
+ {% for class_name in %w[ProcNotation Macro OffsetOf RespondsTo
433
452
  Select ImplicitObj AnnotationDef While Until UninitializedVar
434
- ProcPointer Self Yield LibDef FunDef TypeDef CStructOrUnionDef
453
+ ProcPointer Self LibDef FunDef TypeDef CStructOrUnionDef
435
454
  ExternalVar Alias Metaclass Cast NilableCast TypeOf Annotation
436
455
  Underscore MagicConstant Asm AsmOperand] %}
437
456
  class {{class_name.id}} < ASTNode
438
457
  def to_rb
439
- Rb::AST::EmptyNode.new(self.class.name)
458
+ Rb::AST::EmptyNode.new(self.class.name,@location)
440
459
  end
441
460
  end
442
461
  {% end %}
443
462
 
444
- {% for class_name in %w[PointerOf SizeOf InstanceSizeOf Out MacroVerbatim DoubleSplat] %}
463
+ {% for class_name in %w[PointerOf SizeOf InstanceSizeOf Out MacroVerbatim] %}
445
464
  class {{class_name.id}} < UnaryExpression
446
465
  def to_rb
447
- Rb::AST::EmptyNode.new(self.class.name)
466
+ Rb::AST::EmptyNode.new(self.class.name,@location)
448
467
  end
449
468
  end
450
469
  {% end %}