mvinl 0.1.3

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f891e7bb1683b84d918155e32b06fdf03ae4d00791676e4b1dc467c30d495b90
4
+ data.tar.gz: c96e8a9930ed532580014843594d70d3fb025089fdd06708e9440b5316c2a772
5
+ SHA512:
6
+ metadata.gz: febf482245e910fe310efae6a5aaaa115769830475678ba8b0e8b0d65dee6b0b4e22f5a4d9d5e5236f5a8e35e0125f55d406a155c6e2b3e4441ced8f7dfe05de
7
+ data.tar.gz: fb604a7c640da0406c0d0a1190ba0a684491728cd1b9b666da5e870bd754b50d8ebde6ad5a2e3dfea0aecab98e98fc60e7dfbb3d35f94526d5294e981ef91bb1
data/.gitignore ADDED
@@ -0,0 +1,26 @@
1
+ *
2
+ !*/
3
+ !.gitignore
4
+
5
+ # Package
6
+ !README.md
7
+ !LICENSE
8
+ !.ruby-version
9
+ !Gemfile
10
+ !mvinl.gemspec
11
+ !Rakefile
12
+ !rakelib/[a-z]*.rake
13
+ !edit/mvinl.vim
14
+
15
+ # Executables
16
+ !bin/imvnl
17
+
18
+ # Library code
19
+ !lib/mvinl.rb
20
+ !lib/mvinl/[a-z]*.rb
21
+
22
+ !syntax/mvinl.y
23
+
24
+ # Spec
25
+ !spec/[a-z]*.mvnl
26
+ !spec/[a-z]*.rb
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ gem 'racc', '~> 1.8.1'
6
+ gem 'rake', '~> 13.2'
7
+
8
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Daniel Sierpiński
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # MVinl
2
+
3
+ A mini stack configuration language.
4
+
5
+ *Mini Vinl is not Lisp*
6
+
7
+ ## Install
8
+
9
+ MVinl is packaged as gem. To install it from RubyGems.org go
10
+
11
+ ```
12
+ gem install mvinl
13
+ ```
14
+
15
+ or build and install it from this repo if you have it downloaded
16
+
17
+ ```
18
+ gem build
19
+ gem install ./mvinl-0.1.0.gem
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ Use `MVinl.eval` or `MVinl.eval_from_file` to evaluate mvinl code.
25
+
26
+ `imvnl` is an interactive shell for mvinl. It's not really how the language
27
+ suppose to be used but it's useful for quckly testing expressions.
28
+
29
+ Vinl execution returns a hash similar to YAML or JSON. The point is to create a
30
+ configuration structure to initiate objects in an application, like a game
31
+ engine.
32
+
33
+ The main elements that construct the resulting structure are groups and
34
+ properties. Groups typically sort objects into data categories, such as states.
35
+ Properties can be thought of as object constructors.
36
+
37
+ **Example:**
38
+
39
+ ``` mvinl
40
+ def (center x (/ x 2))
41
+
42
+ @start
43
+ SplashScreen 'path/to/image'.
44
+
45
+ @second
46
+ Buttom (center 1920)
47
+ (center 1080)
48
+ "Hello, MVinl!"
49
+ font_size: 21 # END_TAG is optional
50
+ ```
51
+
52
+ ## Contribute
53
+
54
+ I happily accept suggestions and changes. Please leave bug rapports
55
+ [here](https://github.com/513ry/mvinl/issues).
56
+
57
+ ## License
58
+
59
+ MVinl is a free software distributed under MIT license. Read LICENSE file for
60
+ legal notice.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ task default: %w[spec]
2
+
3
+ task :spec do
4
+ rspec
5
+ end
data/bin/imvnl ADDED
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen-string-literal: true
3
+
4
+ =begin engine.rb
5
+ Copyright (c) 2018, 2024, Daniel Sierpiński All rights reserved.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in
15
+ all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ THE SOFTWARE.
24
+ =end
25
+
26
+ require 'readline'
27
+ require 'pry'
28
+ require 'mvinl/lexer'
29
+ require 'mvinl/parser'
30
+ require 'mvinl/info'
31
+
32
+ PSL = "mvnl(#{MVinl::Version})".freeze
33
+ PS1 = "#{PSL}>".freeze
34
+
35
+ module MVinl::REPL
36
+ LEXER = MVinl::Lexer.new('')
37
+ PARSER = MVinl::Parser.new(LEXER)
38
+
39
+ def self.run
40
+ while (input = Readline.readline("#{PS1} ", true))
41
+ Readline::HISTORY.pop if input.strip.empty?
42
+
43
+ if input == '^' || input == 'exit'
44
+ PARSER.finalize!
45
+ break if PARSER.parsing_done?
46
+ else
47
+ LEXER.feed input
48
+ end
49
+
50
+ begin
51
+ out = PARSER.parse
52
+ print '=> '
53
+ pp out
54
+ rescue MVinl::LexerError => e
55
+ warn e.message
56
+ rescue MVinl::ParserError => e
57
+ warn e.message
58
+ rescue Racc::ParseError => e
59
+ warn e.message
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ MVinl::REPL.run
data/edit/mvinl.vim ADDED
@@ -0,0 +1,63 @@
1
+ " Vim syntax file
2
+ " Language: MVinl
3
+ " Maintainer: Daniel Sierpinski
4
+ " Last Change: Dec 04, 2024
5
+ " Version: 1
6
+ "
7
+ " Thanks to the authors of lisp.vim
8
+ " ---------------------------------------------------------------------
9
+ autocmd BufNewFile,BufRead *.mvnl set filetype=mvinl
10
+
11
+ let s:id = "[a-zA-Z_][a-zA-Z0-9_]*"
12
+
13
+ syn keyword mvinlKeyword style as def
14
+ execute 'syn match mvinlIdentifier "' . s:id . '"'
15
+ syn match mvinlNumber "[0-9]\+"
16
+ execute 'syn match mvinlSymbol ":' . s:id . '"'
17
+ syn match mvinlString "\"((?:\\.|[^\"\\])*)\""
18
+ execute 'syn match mvinlKeywordArg "' . s:id . ':"'
19
+ execute 'syn match mvinlGroup "@' . s:id . '"'
20
+ syn match mvinlComment "#.*\n"
21
+ syn match mvinlOper "[+\-*/%]" contained
22
+
23
+ unlet s:id
24
+
25
+ syn cluster mvinlValue contains=mvnilString,mvinlNumber,mvinlSymbol
26
+ syn cluster mvinlLambda contains=@mvinlValue,mvinlIdentifier,mvinlOper
27
+
28
+ " ---------------------------------------------------------------------
29
+ " Match polish notation:
30
+ syn region mvinlParen0 matchgroup=hlLevel0 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen1
31
+ syn region mvinlParen1 contained matchgroup=hlLevel1 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen2
32
+ syn region mvinlParen2 contained matchgroup=hlLevel2 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen3
33
+ syn region mvinlParen3 contained matchgroup=hlLevel3 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen4
34
+ syn region mvinlParen4 contained matchgroup=hlLevel4 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen5
35
+ syn region mvinlParen5 contained matchgroup=hlLevel5 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen6
36
+ syn region mvinlParen6 contained matchgroup=hlLevel6 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen7
37
+ syn region mvinlParen7 contained matchgroup=hlLevel7 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen8
38
+ syn region mvinlParen8 contained matchgroup=hlLevel8 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen9
39
+ syn region mvinlParen9 contained matchgroup=hlLevel9 start="`\=(" end=")" skip="|.\{-}|" contains=@mvinlLambda,mvinlParen0
40
+
41
+ hi mvinlOperType guifg=#970096 ctermfg=95
42
+
43
+ hi! link mvinlOper mvinlOperType
44
+ hi link mvinlKeyword Keyword
45
+ hi link mvinlIdentifier Type
46
+ hi link mvinlNumber Number
47
+ hi link mvinlSymbol Constant
48
+ hi link mvinlString String
49
+ hi link mvinlKeywordArg Define
50
+ hi link mvinlGroup Identifier
51
+ hi link mvinlComment Comment
52
+
53
+ hi def hlLevel0 ctermfg=red guifg=red1
54
+ hi def hlLevel1 ctermfg=yellow guifg=orange1
55
+ hi def hlLevel2 ctermfg=green guifg=yellow1
56
+ hi def hlLevel3 ctermfg=cyan guifg=greenyellow
57
+ hi def hlLevel4 ctermfg=magenta guifg=green1
58
+ hi def hlLevel5 ctermfg=red guifg=springgreen1
59
+ hi def hlLevel6 ctermfg=yellow guifg=cyan1
60
+ hi def hlLevel7 ctermfg=green guifg=slateblue1
61
+ hi def hlLevel8 ctermfg=cyan guifg=magenta1
62
+ hi def hlLevel9 ctermfg=magenta guifg=purple1
63
+
data/lib/mvinl/info.rb ADDED
@@ -0,0 +1,12 @@
1
+ # frozen-string-literal: true
2
+
3
+ # engine.rb
4
+ # Copyright (c) 2024, Daniel Sierpiński All rights reserved.
5
+ #
6
+ # See Copyright Notice in mvnil.rb
7
+
8
+ module MVinl
9
+ VERSION = '0.1.3'
10
+ Version = VERSION
11
+ Copyright = 'Copyright (c) 2024, Daniel Sierpiński'
12
+ end
@@ -0,0 +1,155 @@
1
+ # frozen-string-literal: true
2
+
3
+ =begin engine.rb
4
+ Copyright (c) 2024, Daniel Sierpiński All rights reserved.
5
+
6
+ See Copyright Notice in mvnil.rb
7
+ =end
8
+
9
+ require 'strscan'
10
+
11
+ module MVinl
12
+ class LexerError < StandardError; end
13
+ class UnexpectedTokenError < LexerError; end
14
+
15
+ class Lexer
16
+ attr_reader :eos
17
+
18
+ ID_REGEX = /[a-zA-Z_][a-zA-Z0-9_]*/
19
+
20
+ RESERVED = %w[def as style].freeze
21
+
22
+ TOKENS = {
23
+ KEYWORD: /#{RESERVED[0]}|#{RESERVED[1]}|#{RESERVED[2]}/,
24
+ OPEN_PAREN: /\(/,
25
+ CLOSE_PAREN: /\)/,
26
+ NEW_LINE: /(?:[ \t]*(?:\r?\n)[ \t]*)+/,
27
+ WHITESPACE: /[ \t]/,
28
+ KEYWORD_ARG: /(#{ID_REGEX}):/,
29
+ ID: ID_REGEX,
30
+ GROUP: /@(#{ID_REGEX})/,
31
+ NUMBER: /[+-]?\d+/,
32
+ STRING: /"((?:\\.|[^"\\])*)"/,
33
+ SYMBOL: /:(#{ID_REGEX})/,
34
+ COMMENT: /#/,
35
+ OPER: %r{[+\-*/%]},
36
+ END_TAG: /\./
37
+ }.freeze
38
+
39
+ def initialize(input)
40
+ @ss = StringScanner.new(input)
41
+ @args_n = 0
42
+ @in_group = false
43
+ @eos = false
44
+ end
45
+
46
+ def feed(input)
47
+ @ss = StringScanner.new(input)
48
+ end
49
+
50
+ def next_token
51
+ return process_eos if @ss.eos?
52
+
53
+ TOKENS.each do |type, regex|
54
+ if @ss.scan regex
55
+ @last_type = type
56
+ break
57
+ end
58
+ end
59
+ case @last_type
60
+ when :NEW_LINE
61
+ return next_token if continuation_line?
62
+
63
+ [:END_TAG, "\n"]
64
+ when :WHITESPACE
65
+ # Whitespace (' ' and '\t') does nothing in mvnl 0.1. I handle them
66
+ # though as indentation plays a role in 0.2 to predict position of elements
67
+ next_token
68
+ when :COMMENT
69
+ skip_to_next_line
70
+ next_token
71
+ when :OPEN_PAREN then [:OPEN_PAREN, '(']
72
+ when :CLOSE_PAREN
73
+ unless Parser::STATE[:depth].positive?
74
+ raise UnexpectedTokenError, 'CLOSE_PARAM found winth no matching OPEN_PARAM'
75
+ end
76
+
77
+ [:CLOSE_PAREN, ')']
78
+ when :OPER
79
+ unless Parser::STATE[:depth].positive?
80
+ raise UnexpectedTokenError, 'OPER found with no matching OPEN_PARAM'
81
+ end
82
+
83
+ [:OPER, @ss.matched]
84
+ when :KEYWORD
85
+ return [:DEF, @ss.matched] if @ss.matched == 'def'
86
+
87
+ [:KEYWORD, @ss.matched]
88
+ when :KEYWORD_ARG
89
+ if !Parser::STATE[:in_prop]
90
+ raise UnexpectedTokenError, 'Looking for identifier but found KEYWORD_ARG'
91
+ elsif Parser::STATE[:in_keyword_arg]
92
+ raise UnexpectedTokenError, 'Looking for a keyword argument value but found KEYWORD_ARG'
93
+ end
94
+
95
+ [:KEYWORD_ARG, @ss[1]]
96
+ when :GROUP
97
+ # Group gets canceled whenever encountered another group id or a matching end tag
98
+ if Parser::STATE[:in_keyword_arg]
99
+ raise UnexpectedTokenError, 'Looking for a keyword argument value but found GROUP'
100
+ end
101
+
102
+ @in_group = true
103
+ [:GROUP, @ss[1]]
104
+ when :ID then [:ID, @ss.matched]
105
+ when :NUMBER, :STRING, :SYMBOL
106
+ # Values can't be used outside an property or a lambda
107
+ if !Parser::STATE[:in_prop] && !Parser::STATE[:depth].positive?
108
+ raise UnexpectedTokenError, "Looking for ID or OPEN_PAREN but found #{@last_type}"
109
+ elsif !Parser::STATE[:in_keyword_arg] && Parser::STATE[:keyword_arg_depth].positive? &&
110
+ !Parser::STATE[:depth].positive?
111
+ raise UnexpectedTokenError, "Looking for END_TAG or KEYWORD_ARG but found #{@last_type}"
112
+ end
113
+
114
+ [@last_type, @ss[1] || @ss.matched]
115
+ when :END_TAG then [:END_TAG, '.']
116
+ else
117
+ raise UnexpectedTokenError, "Unexpected character: '#{@ss.getch}'"
118
+ end
119
+ rescue LexerError => e
120
+ warn "Syntax error at #{@ss.charpos - @ss.matched_size}: #{e}"
121
+ end
122
+
123
+ def tokenize
124
+ tokens = []
125
+ while (token = next_token)
126
+ warn "Tokenize: #{token}"
127
+ tokens << token
128
+ end
129
+ tokens
130
+ end
131
+
132
+ private
133
+
134
+ def continuation_line?
135
+ return true unless @in_group
136
+
137
+ # Auto end properties
138
+ lookahead = @ss.check(/\A(?:#{TOKENS[:GROUP]}|#{TOKENS[:ID]}$|#{TOKENS[:END_TAG]}|#{TOKENS[:NEW_LINE]})/)
139
+ warn "Continue? in_prop?: #{Parser::STATE[:in_prop].inspect}, lookahead: #{lookahead.inspect}"
140
+ Parser::STATE[:in_prop] ? !lookahead : true
141
+ end
142
+
143
+ # Move the cursor to the next new line tag
144
+ def skip_to_next_line
145
+ @ss.scan_until(/\n/) || @ss.terminate
146
+ end
147
+
148
+ def process_eos
149
+ return if @eos
150
+
151
+ @eos = true
152
+ [false, '$']
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,43 @@
1
+ # frozen-string-literal: true
2
+
3
+ =begin engine.rb
4
+ Copyright (c) 2024, Daniel Sierpiński All rights reserved.
5
+
6
+ See Copyright Notice in mvnil.rb
7
+ =end
8
+
9
+ require_relative '../../syntax/mvinl.tab'
10
+
11
+ class MVinl::Parser < MVinl::Program
12
+ def initialize(lexer, debug: false)
13
+ @yydebug = debug
14
+ @lexer = lexer
15
+ @tokens = []
16
+ @done = false
17
+ super()
18
+ end
19
+
20
+ def next_token
21
+ if @tokens.empty?
22
+ @lexer.next_token
23
+ else
24
+ @tokens.shift
25
+ end
26
+ end
27
+
28
+ def enqueue_token(token)
29
+ @tokens << token
30
+ end
31
+
32
+ def finalize!
33
+ @done = true
34
+ end
35
+
36
+ def parsing_done?
37
+ @done && @tokens.empty?
38
+ end
39
+
40
+ def parse
41
+ do_parse
42
+ end
43
+ end
data/lib/mvinl.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen-string-literal: true
2
+
3
+ =begin engine.rb
4
+ Copyright (c) 2018, 2024, Daniel Sierpiński All rights reserved.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
23
+ =end
24
+
25
+ require 'mvinl/parser'
26
+ require 'mvinl/lexer'
27
+
28
+ module MVinl
29
+ def self.eval(input)
30
+ parser = Parser.new(Lexer.new(input))
31
+ parser.parse
32
+ end
33
+
34
+ def self.eval_from_file(path)
35
+ self.eval File.read(path)
36
+ end
37
+ end
data/mvinl.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # frozen-string-literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'mvinl/info'
6
+
7
+ GRAMMAR_FILE = 'syntax/mvinl.y'
8
+ COMPILED_FILE = 'syntax/mvinl.tab.rb'
9
+
10
+ Gem::Specification.new do |s|
11
+ s.name = 'mvinl'
12
+ s.version = MVinl::VERSION
13
+ s.authors = ['siery']
14
+ s.email = ['siery@comic.com']
15
+ s.summary = 'A simple configuration language made with RACC'
16
+ s.homepage = 'https://rubygems.org/gems/mvinl'
17
+ s.license = 'MIT'
18
+ s.metadata = { 'source_code_uri' => 'https://github.com/513ry/mvinl' }
19
+ s.required_ruby_version = '>= 3.2.0'
20
+
21
+ # Sify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ s.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|s|features)/}) }
25
+ end
26
+ # Compile syntax file
27
+ s.files.delete(GRAMMAR_FILE)
28
+ s.files << COMPILED_FILE
29
+ s.require_paths = %w[lib bin s rakelib syntax]
30
+ s.executables << 'imvnl'
31
+
32
+ s.add_dependency 'pp', '~> 0.6.2'
33
+ end
@@ -0,0 +1,8 @@
1
+ # frozen-string-literal: true
2
+
3
+ GRAMMAR_FILE = 'syntax/mvinl.y'
4
+ COMPILED_FILE = 'syntax/mvinl.tab.rb'
5
+
6
+ task 'build' do
7
+ system('racc', GRAMMAR_FILE, '-o', COMPILED_FILE)
8
+ end
data/spec/stack.mvnl ADDED
@@ -0,0 +1,21 @@
1
+ #
2
+ #
3
+ #
4
+ # MVinl stack configuration
5
+
6
+ # Definition with a single argument
7
+ def (mins x (% x 60))
8
+
9
+ # Definition with multiple arguments
10
+ def (perc x n (/ (* x 100) n))
11
+
12
+ @menu # First group runs as the initial state
13
+ Menu
14
+ New_Game: :state_next
15
+ Exit: :abord
16
+
17
+ @game
18
+ Mouse
19
+ Board 3 (+ 1 (+ 1 (+ 1)))
20
+ Button "󰮱 Hello Vinl!"
21
+ line_height: (perc 2 8) padding: (* 2 4)
@@ -0,0 +1,519 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by Racc 1.8.1
4
+ # from Racc grammar file "mvinl.y".
5
+ #
6
+
7
+ require 'racc/parser.rb'
8
+ module MVinl
9
+ class Program < Racc::Parser
10
+
11
+ module_eval(<<'...end mvinl.y/module_eval...', 'mvinl.y', 105)
12
+
13
+ FUNCTIONS = {}
14
+ STATE = {
15
+ in_prop: false,
16
+ in_keyword_arg: false,
17
+ keyword_arg_depth: 0,
18
+ depth: 0
19
+ }
20
+
21
+ class MVinl::ParserError < StandardError; end
22
+
23
+ private
24
+
25
+ def create_property(id, positional_args = [], keyword_args = {})
26
+ STATE[:in_prop] = false
27
+ {id => [positional_args, keyword_args]}
28
+ end
29
+
30
+ def create_group(properties)
31
+ properties || Hash.new
32
+ end
33
+
34
+ def define_function(name, args, body)
35
+ FUNCTIONS[name.to_sym] = {args: args, body: body}
36
+ nil
37
+ end
38
+
39
+ def evaluate_pn(operator, operands, context = {})
40
+ operands.map! do |op|
41
+ if op.is_a?(Array)
42
+ evaluate_pn(op[0], op[1..], context) # Nested PN expression
43
+ elsif context.key?(op)
44
+ context[op] # Function identifier
45
+ else
46
+ op # Literal value (e.g., NUMBER or STRING)
47
+ end
48
+ end
49
+
50
+ if FUNCTIONS.key?(operator.to_sym)
51
+ function = FUNCTIONS[operator.to_sym]
52
+ raise MVinl::ParserError, "Argument mismatch for #{operator}" if operands.size != function[:args].size
53
+
54
+ # Map arguments to operands
55
+ new_context = function[:args].zip(operands).to_h
56
+ # Replace symbols in body with context values
57
+ function = replace_symbols(function[:body], new_context)
58
+ # Recursive evaluation
59
+ evaluate_pn(function[0], function[1..], new_context)
60
+ else
61
+ begin
62
+ operands.reduce(operator.to_sym)
63
+ rescue NoMethodError
64
+ raise MVinl::ParserError, "Unknown operator: #{operator}"
65
+ end
66
+ end
67
+ end
68
+
69
+ def replace_symbols(array, replacements)
70
+ array.map do |element|
71
+ if element.is_a?(Array)
72
+ replace_symbols(element, replacements)
73
+ elsif element.is_a?(Symbol) && replacements.key?(element)
74
+ replacements[element]
75
+ else
76
+ element
77
+ end
78
+ end
79
+ end
80
+ ...end mvinl.y/module_eval...
81
+ ##### State transition tables begin ###
82
+
83
+ racc_action_table = [
84
+ 2, 8, 5, 6, 30, 26, 27, 28, 15, 7,
85
+ 11, 11, 15, 15, 26, 27, 28, 15, 17, 11,
86
+ 41, 48, 15, 26, 27, 28, 37, 41, 11, 41,
87
+ 48, 15, 26, 27, 28, 43, nil, 11, 41, 15,
88
+ 15, 26, 27, 28, nil, nil, 11, 41, nil, 15,
89
+ -14, -14, -14, -14, nil, nil, 11, -16, 26, 27,
90
+ 28, nil, nil, 11, 26, 27, 28, nil, nil, 11 ]
91
+
92
+ racc_action_check = [
93
+ 1, 2, 1, 1, 20, 21, 21, 21, 20, 1,
94
+ 21, 7, 9, 21, 38, 38, 38, 10, 12, 38,
95
+ 38, 38, 38, 39, 39, 39, 22, 31, 39, 39,
96
+ 39, 39, 50, 50, 50, 32, nil, 50, 50, 32,
97
+ 50, 51, 51, 51, nil, nil, 51, 51, nil, 51,
98
+ 13, 13, 13, 13, nil, nil, 13, 18, 18, 18,
99
+ 18, nil, nil, 18, 36, 36, 36, nil, nil, 36 ]
100
+
101
+ racc_action_pointer = [
102
+ nil, 0, 1, nil, nil, nil, nil, 0, nil, -2,
103
+ 3, nil, 14, 45, nil, nil, nil, nil, 52, nil,
104
+ -6, -1, 21, nil, nil, nil, nil, nil, nil, nil,
105
+ nil, 15, 25, nil, nil, nil, 58, nil, 8, 17,
106
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
107
+ 26, 35, nil, nil, nil ]
108
+
109
+ racc_action_default = [
110
+ -1, -41, -41, -2, -3, -4, -6, -41, 55, -5,
111
+ -41, -30, -7, -9, -13, -40, -32, -8, -10, -12,
112
+ -41, -41, -11, -15, -20, -21, -22, -23, -24, -36,
113
+ -36, -35, -41, -33, -34, -17, -41, -19, -41, -41,
114
+ -25, -31, -32, -32, -18, -28, -37, -38, -39, -29,
115
+ -41, -41, -26, -35, -27 ]
116
+
117
+ racc_goto_table = [
118
+ 10, 14, 16, 34, 23, 38, 39, 1, 21, 40,
119
+ 3, 4, 29, 9, 32, 12, 45, 49, 13, 18,
120
+ 22, 19, 44, 35, 42, 36, 31, nil, 52, 54,
121
+ 47, 47, 34, 34, 50, 51, nil, nil, nil, nil,
122
+ nil, nil, nil, 32, 32 ]
123
+
124
+ racc_goto_check = [
125
+ 15, 10, 10, 14, 11, 19, 19, 1, 16, 18,
126
+ 2, 3, 10, 4, 15, 5, 18, 18, 6, 7,
127
+ 8, 9, 11, 12, 10, 13, 17, nil, 18, 18,
128
+ 10, 10, 14, 14, 16, 16, nil, nil, nil, nil,
129
+ nil, nil, nil, 15, 15 ]
130
+
131
+ racc_goto_pointer = [
132
+ nil, 7, 9, 10, 7, 6, 9, 6, 2, 8,
133
+ -8, -14, 1, 3, -18, -7, -8, 5, -22, -24 ]
134
+
135
+ racc_goto_default = [
136
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, 25,
137
+ 33, 46, nil, nil, 24, 20, nil, 53, nil, nil ]
138
+
139
+ racc_reduce_table = [
140
+ 0, 0, :racc_error,
141
+ 0, 16, :_reduce_1,
142
+ 2, 16, :_reduce_2,
143
+ 2, 16, :_reduce_3,
144
+ 2, 16, :_reduce_4,
145
+ 2, 17, :_reduce_5,
146
+ 0, 19, :_reduce_6,
147
+ 2, 19, :_reduce_7,
148
+ 3, 19, :_reduce_8,
149
+ 1, 20, :_reduce_9,
150
+ 2, 20, :_reduce_10,
151
+ 3, 20, :_reduce_11,
152
+ 2, 20, :_reduce_12,
153
+ 1, 21, :_reduce_13,
154
+ 0, 22, :_reduce_14,
155
+ 2, 22, :_reduce_15,
156
+ 0, 23, :_reduce_16,
157
+ 2, 23, :_reduce_17,
158
+ 2, 27, :_reduce_18,
159
+ 1, 28, :_reduce_19,
160
+ 1, 26, :_reduce_20,
161
+ 1, 26, :_reduce_21,
162
+ 1, 29, :_reduce_22,
163
+ 1, 29, :_reduce_23,
164
+ 1, 29, :_reduce_24,
165
+ 6, 18, :_reduce_25,
166
+ 4, 32, :_reduce_26,
167
+ 4, 32, :_reduce_27,
168
+ 4, 24, :_reduce_28,
169
+ 4, 24, :_reduce_29,
170
+ 1, 30, :_reduce_30,
171
+ 1, 33, :_reduce_31,
172
+ 0, 31, :_reduce_32,
173
+ 2, 31, :_reduce_33,
174
+ 2, 31, :_reduce_34,
175
+ 2, 31, :_reduce_35,
176
+ 0, 34, :_reduce_36,
177
+ 2, 34, :_reduce_37,
178
+ 2, 34, :_reduce_38,
179
+ 2, 34, :_reduce_39,
180
+ 1, 25, :_reduce_40 ]
181
+
182
+ racc_reduce_n = 41
183
+
184
+ racc_shift_n = 55
185
+
186
+ racc_token_table = {
187
+ false => 0,
188
+ :error => 1,
189
+ :EOS => 2,
190
+ :GROUP => 3,
191
+ :END_TAG => 4,
192
+ :KEYWORD_ARG => 5,
193
+ :NUMBER => 6,
194
+ :STRING => 7,
195
+ :SYMBOL => 8,
196
+ :DEF => 9,
197
+ :OPER => 10,
198
+ :OPEN_PAREN => 11,
199
+ :CLOSE_PAREN => 12,
200
+ :polish_notation => 13,
201
+ :ID => 14 }
202
+
203
+ racc_nt_base = 15
204
+
205
+ racc_use_result_var = false
206
+
207
+ Racc_arg = [
208
+ racc_action_table,
209
+ racc_action_check,
210
+ racc_action_default,
211
+ racc_action_pointer,
212
+ racc_goto_table,
213
+ racc_goto_check,
214
+ racc_goto_default,
215
+ racc_goto_pointer,
216
+ racc_nt_base,
217
+ racc_reduce_table,
218
+ racc_token_table,
219
+ racc_shift_n,
220
+ racc_reduce_n,
221
+ racc_use_result_var ]
222
+ Ractor.make_shareable(Racc_arg) if defined?(Ractor)
223
+
224
+ Racc_token_to_s_table = [
225
+ "$end",
226
+ "error",
227
+ "EOS",
228
+ "GROUP",
229
+ "END_TAG",
230
+ "KEYWORD_ARG",
231
+ "NUMBER",
232
+ "STRING",
233
+ "SYMBOL",
234
+ "DEF",
235
+ "OPER",
236
+ "OPEN_PAREN",
237
+ "CLOSE_PAREN",
238
+ "polish_notation",
239
+ "ID",
240
+ "$start",
241
+ "program",
242
+ "group",
243
+ "function_def",
244
+ "properties",
245
+ "property",
246
+ "prop_id",
247
+ "positional_args",
248
+ "keyword_args",
249
+ "lambda",
250
+ "identifier",
251
+ "super_value",
252
+ "keyword_arg",
253
+ "keyword_arg_id",
254
+ "value",
255
+ "open_paren",
256
+ "args",
257
+ "polish_notation_def",
258
+ "close_paren",
259
+ "params" ]
260
+ Ractor.make_shareable(Racc_token_to_s_table) if defined?(Ractor)
261
+
262
+ Racc_debug_parser = false
263
+
264
+ ##### State transition tables end #####
265
+
266
+ # reduce 0 omitted
267
+
268
+ module_eval(<<'.,.,', 'mvinl.y', 12)
269
+ def _reduce_1(val, _values)
270
+ Hash.new
271
+ end
272
+ .,.,
273
+
274
+ module_eval(<<'.,.,', 'mvinl.y', 13)
275
+ def _reduce_2(val, _values)
276
+ val[0].merge(val[1])
277
+ end
278
+ .,.,
279
+
280
+ module_eval(<<'.,.,', 'mvinl.y', 14)
281
+ def _reduce_3(val, _values)
282
+ val[0]
283
+ end
284
+ .,.,
285
+
286
+ module_eval(<<'.,.,', 'mvinl.y', 15)
287
+ def _reduce_4(val, _values)
288
+ val[0]
289
+ end
290
+ .,.,
291
+
292
+ module_eval(<<'.,.,', 'mvinl.y', 18)
293
+ def _reduce_5(val, _values)
294
+ {val[0].to_sym => create_group(val[1])}
295
+ end
296
+ .,.,
297
+
298
+ module_eval(<<'.,.,', 'mvinl.y', 21)
299
+ def _reduce_6(val, _values)
300
+ Hash.new
301
+ end
302
+ .,.,
303
+
304
+ module_eval(<<'.,.,', 'mvinl.y', 22)
305
+ def _reduce_7(val, _values)
306
+ val[0].merge(val[1])
307
+ end
308
+ .,.,
309
+
310
+ module_eval(<<'.,.,', 'mvinl.y', 23)
311
+ def _reduce_8(val, _values)
312
+ val[0].merge(val[1])
313
+ end
314
+ .,.,
315
+
316
+ module_eval(<<'.,.,', 'mvinl.y', 26)
317
+ def _reduce_9(val, _values)
318
+ create_property(val[0])
319
+ end
320
+ .,.,
321
+
322
+ module_eval(<<'.,.,', 'mvinl.y', 27)
323
+ def _reduce_10(val, _values)
324
+ create_property(val[0], val[1])
325
+ end
326
+ .,.,
327
+
328
+ module_eval(<<'.,.,', 'mvinl.y', 28)
329
+ def _reduce_11(val, _values)
330
+ create_property(val[0], val[1], val[2])
331
+ end
332
+ .,.,
333
+
334
+ module_eval(<<'.,.,', 'mvinl.y', 29)
335
+ def _reduce_12(val, _values)
336
+ create_property(val[0], val[1])
337
+ end
338
+ .,.,
339
+
340
+ module_eval(<<'.,.,', 'mvinl.y', 32)
341
+ def _reduce_13(val, _values)
342
+ STATE[:in_prop] = true; val[0]
343
+ end
344
+ .,.,
345
+
346
+ module_eval(<<'.,.,', 'mvinl.y', 35)
347
+ def _reduce_14(val, _values)
348
+ Array.new
349
+ end
350
+ .,.,
351
+
352
+ module_eval(<<'.,.,', 'mvinl.y', 36)
353
+ def _reduce_15(val, _values)
354
+ val[0] << val[1]
355
+ end
356
+ .,.,
357
+
358
+ module_eval(<<'.,.,', 'mvinl.y', 39)
359
+ def _reduce_16(val, _values)
360
+ Hash.new
361
+ end
362
+ .,.,
363
+
364
+ module_eval(<<'.,.,', 'mvinl.y', 42)
365
+ def _reduce_17(val, _values)
366
+ STATE[:keyword_arg_depth] = 0
367
+ val[0].merge(val[1])
368
+
369
+ end
370
+ .,.,
371
+
372
+ module_eval(<<'.,.,', 'mvinl.y', 49)
373
+ def _reduce_18(val, _values)
374
+ STATE[:in_keyword_arg] = false
375
+ STATE[:keyword_arg_depth] += 1
376
+ {val[0].to_sym => val[1]}
377
+
378
+ end
379
+ .,.,
380
+
381
+ module_eval(<<'.,.,', 'mvinl.y', 55)
382
+ def _reduce_19(val, _values)
383
+ STATE[:in_keyword_arg] = true; val[0]
384
+ end
385
+ .,.,
386
+
387
+ module_eval(<<'.,.,', 'mvinl.y', 58)
388
+ def _reduce_20(val, _values)
389
+ val[0]
390
+ end
391
+ .,.,
392
+
393
+ module_eval(<<'.,.,', 'mvinl.y', 59)
394
+ def _reduce_21(val, _values)
395
+ val[0]
396
+ end
397
+ .,.,
398
+
399
+ module_eval(<<'.,.,', 'mvinl.y', 62)
400
+ def _reduce_22(val, _values)
401
+ val[0].to_i
402
+ end
403
+ .,.,
404
+
405
+ module_eval(<<'.,.,', 'mvinl.y', 63)
406
+ def _reduce_23(val, _values)
407
+ val[0]
408
+ end
409
+ .,.,
410
+
411
+ module_eval(<<'.,.,', 'mvinl.y', 64)
412
+ def _reduce_24(val, _values)
413
+ val[0].to_sym
414
+ end
415
+ .,.,
416
+
417
+ module_eval(<<'.,.,', 'mvinl.y', 69)
418
+ def _reduce_25(val, _values)
419
+ define_function(val[2], val[3], val[4])
420
+
421
+ end
422
+ .,.,
423
+
424
+ module_eval(<<'.,.,', 'mvinl.y', 73)
425
+ def _reduce_26(val, _values)
426
+ [val[1], *val[2]]
427
+ end
428
+ .,.,
429
+
430
+ module_eval(<<'.,.,', 'mvinl.y', 74)
431
+ def _reduce_27(val, _values)
432
+ [val[1], *val[2]]
433
+ end
434
+ .,.,
435
+
436
+ module_eval(<<'.,.,', 'mvinl.y', 77)
437
+ def _reduce_28(val, _values)
438
+ evaluate_pn(val[1], val[2])
439
+ end
440
+ .,.,
441
+
442
+ module_eval(<<'.,.,', 'mvinl.y', 78)
443
+ def _reduce_29(val, _values)
444
+ evaluate_pn(val[1], val[2])
445
+ end
446
+ .,.,
447
+
448
+ module_eval(<<'.,.,', 'mvinl.y', 81)
449
+ def _reduce_30(val, _values)
450
+ STATE[:depth] += 1
451
+ end
452
+ .,.,
453
+
454
+ module_eval(<<'.,.,', 'mvinl.y', 84)
455
+ def _reduce_31(val, _values)
456
+ STATE[:depth] -= 1
457
+ end
458
+ .,.,
459
+
460
+ module_eval(<<'.,.,', 'mvinl.y', 87)
461
+ def _reduce_32(val, _values)
462
+ Array.new
463
+ end
464
+ .,.,
465
+
466
+ module_eval(<<'.,.,', 'mvinl.y', 88)
467
+ def _reduce_33(val, _values)
468
+ val[0] << val[1]
469
+ end
470
+ .,.,
471
+
472
+ module_eval(<<'.,.,', 'mvinl.y', 89)
473
+ def _reduce_34(val, _values)
474
+ val[0] << val[1]
475
+ end
476
+ .,.,
477
+
478
+ module_eval(<<'.,.,', 'mvinl.y', 90)
479
+ def _reduce_35(val, _values)
480
+ val[0] << val[1]
481
+ end
482
+ .,.,
483
+
484
+ module_eval(<<'.,.,', 'mvinl.y', 93)
485
+ def _reduce_36(val, _values)
486
+ Array.new
487
+ end
488
+ .,.,
489
+
490
+ module_eval(<<'.,.,', 'mvinl.y', 94)
491
+ def _reduce_37(val, _values)
492
+ val[0] << val[1]
493
+ end
494
+ .,.,
495
+
496
+ module_eval(<<'.,.,', 'mvinl.y', 95)
497
+ def _reduce_38(val, _values)
498
+ val[0] << val[1]
499
+ end
500
+ .,.,
501
+
502
+ module_eval(<<'.,.,', 'mvinl.y', 96)
503
+ def _reduce_39(val, _values)
504
+ val[0] << val[1]
505
+ end
506
+ .,.,
507
+
508
+ module_eval(<<'.,.,', 'mvinl.y', 99)
509
+ def _reduce_40(val, _values)
510
+ val[0].to_sym
511
+ end
512
+ .,.,
513
+
514
+ def _reduce_none(val, _values)
515
+ val[0]
516
+ end
517
+
518
+ end # class Program
519
+ end # module MVinl
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mvinl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ platform: ruby
6
+ authors:
7
+ - siery
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-12-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pp
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.6.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.6.2
27
+ description:
28
+ email:
29
+ - siery@comic.com
30
+ executables:
31
+ - imvnl
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".gitignore"
36
+ - ".ruby-version"
37
+ - Gemfile
38
+ - LICENSE
39
+ - README.md
40
+ - Rakefile
41
+ - bin/imvnl
42
+ - edit/mvinl.vim
43
+ - lib/mvinl.rb
44
+ - lib/mvinl/info.rb
45
+ - lib/mvinl/lexer.rb
46
+ - lib/mvinl/parser.rb
47
+ - mvinl.gemspec
48
+ - rakelib/build.rake
49
+ - spec/stack.mvnl
50
+ - syntax/mvinl.tab.rb
51
+ homepage: https://rubygems.org/gems/mvinl
52
+ licenses:
53
+ - MIT
54
+ metadata:
55
+ source_code_uri: https://github.com/513ry/mvinl
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ - bin
61
+ - s
62
+ - rakelib
63
+ - syntax
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 3.2.0
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.5.16
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: A simple configuration language made with RACC
79
+ test_files: []