korekto 1.0.210306
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/korekto +37 -0
- data/lib/korekto.rb +15 -0
- data/lib/korekto/heap.rb +26 -0
- data/lib/korekto/main.rb +141 -0
- data/lib/korekto/statement.rb +196 -0
- data/lib/korekto/statements.rb +41 -0
- data/lib/korekto/symbols.rb +65 -0
- data/lib/korekto/syntax.rb +15 -0
- data/rplugin/ruby/korekto.rb +30 -0
- data/start/korekto/ftdetect/korekto.vim +1 -0
- data/start/korekto/syntax/korekto.vim +12 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 23a256a294cc625c6d701521f8ac80436501dbad3cfcaddc361418454a2aa5d3
|
4
|
+
data.tar.gz: ee6ed801ec1619b0c3c41946f3d1c1831181ab6f8bfbe798174ab3638e021d7b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ea659d6feef95bdb03e76e80dc974ba9a8b6288239525ff6bd141f53e7cdedde1432ab816e4831b35c4b7728ff1b14896ed10915a31badd2093e4b50dd33b1f3
|
7
|
+
data.tar.gz: d191041a84be4e648e4ebb18c376090e6a6ec5c375fe69dea7224532bad19a71d3c9e37db6c07d96243a3206545638bc72d9fb4359cb252ba7d825656aafe8c6
|
data/bin/korekto
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'help_parser'
|
3
|
+
|
4
|
+
OPTIONS = HelpParser['1.0.210306', <<HELP]
|
5
|
+
Usage:
|
6
|
+
korekto [:options+]
|
7
|
+
Options:
|
8
|
+
-h --help
|
9
|
+
-v --version
|
10
|
+
--install \tInstalls the korekto neovim ruby plugin
|
11
|
+
--readme \tOpen korekto github page
|
12
|
+
# Example usage:
|
13
|
+
# cat MARKDOWN.md | korekto
|
14
|
+
# korekto < MARKDOWN.md
|
15
|
+
HELP
|
16
|
+
|
17
|
+
if OPTIONS.install?
|
18
|
+
require 'fileutils'
|
19
|
+
# pack
|
20
|
+
dest = File.expand_path '~/.local/share/nvim/site/pack/korekto'
|
21
|
+
FileUtils.mkdir_p dest
|
22
|
+
src = File.join File.dirname(__dir__), 'start'
|
23
|
+
FileUtils.cp_r src, dest
|
24
|
+
# rplugin
|
25
|
+
dest = File.expand_path '~/.config/nvim'
|
26
|
+
src = File.join File.dirname(__dir__), 'rplugin'
|
27
|
+
FileUtils.cp_r src, dest
|
28
|
+
system "nvim -c ':UpdateRemotePlugins|:quit' > /dev/null"
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
if OPTIONS.readme?
|
32
|
+
Process.detach spawn('xdg-open', 'https://www.github.com/carlosjhr64/korekto')
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'korekto'
|
37
|
+
Korekto.run
|
data/lib/korekto.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Korekto
|
2
|
+
VERSION = '1.0.210306'
|
3
|
+
class Error < Exception; end
|
4
|
+
require 'korekto/symbols'
|
5
|
+
require 'korekto/syntax'
|
6
|
+
require 'korekto/heap'
|
7
|
+
require 'korekto/statement'
|
8
|
+
require 'korekto/statements'
|
9
|
+
require 'korekto/main'
|
10
|
+
def Korekto.run = Korekto::Main.new.run
|
11
|
+
end
|
12
|
+
# Requires:
|
13
|
+
# `ruby`
|
14
|
+
# `nvim`
|
15
|
+
# `xdg-open`
|
data/lib/korekto/heap.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Korekto
|
2
|
+
class Heap
|
3
|
+
def initialize(limit)
|
4
|
+
@limit = limit
|
5
|
+
@combos = (0...limit).to_a.combination(2)
|
6
|
+
.sort{|ij, kl| ij[0]**2 + ij[1]**2 <=> kl[0]**2 + kl[1]**2}
|
7
|
+
.map{|i, j| [[i,j], [j,i]]}
|
8
|
+
.inject([]){|a, ij_kl| a<<ij_kl[0]; a<<ij_kl[1]}
|
9
|
+
@a = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(s)
|
13
|
+
@a.unshift s
|
14
|
+
@a.pop if @a.length > @limit
|
15
|
+
end
|
16
|
+
|
17
|
+
def combos
|
18
|
+
@combos.each do |i,j|
|
19
|
+
next if [i,j].max >= @a.length
|
20
|
+
yield(@a[i], @a[j])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def each = @a.each{yield _1}
|
25
|
+
end
|
26
|
+
end
|
data/lib/korekto/main.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
module Korekto
|
2
|
+
class Main
|
3
|
+
MD_STATEMENT_CODE_TITLE = %r{^(?<statement>.*)\s#(?<code>[A-Z](\d+(/[\w,.]+)?)?)( (?<title>\S.*?\S))?$}
|
4
|
+
MD_FILENAME = %r{^< (?<filename>[/\w\-.]+)$}
|
5
|
+
MD_KLASS_METHOD_DEFINITION = /^(?<klass>::[A-Z]\w+)#(?<method>\w+)(?<definition>[^=]*=.+)$/ # patch
|
6
|
+
MD_RULE = /^[?] (?<rule>\S.*)$/
|
7
|
+
MD_TYPE_PATTERN = %r{^! (?<type>\S+)\s*/(?<pattern>.*)/$}
|
8
|
+
MD_TYPE_VARIABLES = /^! (?<type>\S+)\s*\{(?<variables>\S+( \S+)*)\}$/
|
9
|
+
MD_KEY_VALUE = /^! (?<key>\w+):\s*'(?<value>.*)'$/
|
10
|
+
|
11
|
+
M_FENCE = /^```\s*$/
|
12
|
+
M_COMMENT_LINE = /^\s*#/
|
13
|
+
|
14
|
+
BACKUPS = {}
|
15
|
+
|
16
|
+
def initialize(filename='-', statements: Statements.new, imports: [])
|
17
|
+
@filename,@statements,@imports = filename,statements,imports
|
18
|
+
@imports.push @filename
|
19
|
+
@line,@active = nil,false
|
20
|
+
@m_fence_korekto = /^```korekto$/
|
21
|
+
end
|
22
|
+
|
23
|
+
def type_pattern(type, pattern)
|
24
|
+
t2p = @statements.symbols.t2p
|
25
|
+
raise Error, "type #{type} in use" if t2p.has_key? type
|
26
|
+
t2p[type] = pattern
|
27
|
+
end
|
28
|
+
|
29
|
+
def type_variables(type, variables)
|
30
|
+
v2t,t2p = @statements.symbols.v2t,@statements.symbols.t2p
|
31
|
+
pattern = t2p[type]
|
32
|
+
raise Error, "type #{type} not defined" unless pattern
|
33
|
+
variables.each do |variable|
|
34
|
+
raise Error, "variable #{variable} in use" if v2t.has_key? variable
|
35
|
+
v2t[variable] = type
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def active?
|
40
|
+
case @line
|
41
|
+
when @m_fence_korekto
|
42
|
+
raise Error, 'unexpected fence' if @active
|
43
|
+
@active = true
|
44
|
+
false
|
45
|
+
when M_FENCE
|
46
|
+
@active = false
|
47
|
+
false
|
48
|
+
else
|
49
|
+
@active and not M_COMMENT_LINE.match?(@line)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def patch(klass, method, definition)
|
54
|
+
raise Error, "overrides: #{klass}##{method}" if eval(klass).method_defined? method
|
55
|
+
eval <<~EVAL
|
56
|
+
class #{klass}
|
57
|
+
def #{method}#{definition}
|
58
|
+
end
|
59
|
+
EVAL
|
60
|
+
end
|
61
|
+
|
62
|
+
def key_value(key, value)
|
63
|
+
case key
|
64
|
+
when 'scanner'
|
65
|
+
@statements.symbols.set_scanner value
|
66
|
+
when 'fence'
|
67
|
+
@m_fence_korekto = Regexp.new "^```#{value}$"
|
68
|
+
when 'save'
|
69
|
+
BACKUPS[value] = Marshal.dump(@statements)
|
70
|
+
when 'restore'
|
71
|
+
if backup = BACKUPS[value]
|
72
|
+
@statements = Marshal.load(backup)
|
73
|
+
else
|
74
|
+
raise Error, "nothing saved as '#{value}'"
|
75
|
+
end
|
76
|
+
else
|
77
|
+
raise Error, "key '#{key}' not implemented"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def preprocess?
|
82
|
+
case @line
|
83
|
+
when MD_FILENAME
|
84
|
+
filename = $~[:filename].strip
|
85
|
+
unless @imports.include? filename
|
86
|
+
Main.new(filename, statements:@statements, imports:@imports).run
|
87
|
+
end
|
88
|
+
when MD_KLASS_METHOD_DEFINITION
|
89
|
+
patch($~[:klass],$~[:method],$~[:definition])
|
90
|
+
when MD_RULE
|
91
|
+
@statements.syntax.push $~[:rule].strip
|
92
|
+
when MD_TYPE_PATTERN
|
93
|
+
type_pattern($~[:type], $~[:pattern])
|
94
|
+
when MD_TYPE_VARIABLES
|
95
|
+
type_variables($~[:type], $~[:variables].split)
|
96
|
+
when MD_KEY_VALUE
|
97
|
+
key_value($~[:key], $~[:value])
|
98
|
+
else
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
true
|
102
|
+
end
|
103
|
+
|
104
|
+
def parse(lines)
|
105
|
+
statement_number = line_number = 0
|
106
|
+
while @line = lines.shift
|
107
|
+
begin
|
108
|
+
line_number += 1
|
109
|
+
next unless active?
|
110
|
+
next if preprocess?
|
111
|
+
if md = MD_STATEMENT_CODE_TITLE.match(@line)
|
112
|
+
statement_number += 1
|
113
|
+
code,title = @statements.add(md[:statement].strip,
|
114
|
+
md[:code],
|
115
|
+
md[:title],
|
116
|
+
@filename,
|
117
|
+
statement_number)
|
118
|
+
puts "#{@filename}:#{line_number}:#{code}:#{title}"
|
119
|
+
else
|
120
|
+
raise Error, 'unrecognized korekto line'
|
121
|
+
end
|
122
|
+
rescue Error
|
123
|
+
puts "#{@filename}:#{line_number}:!:#{$!.message}"
|
124
|
+
exit 65
|
125
|
+
rescue
|
126
|
+
puts "#{@filename}:#{line_number}:?:#{$!.message}"
|
127
|
+
$stderr.puts $!.backtrace
|
128
|
+
exit 1
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def run
|
134
|
+
if @filename=='-'
|
135
|
+
parse $stdin.readlines(chomp: true)
|
136
|
+
else
|
137
|
+
parse IO.readlines(@filename, chomp: true)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
module Korekto
|
2
|
+
class Statement
|
3
|
+
attr_reader :code,:title,:regexp,:filename,:statement_number
|
4
|
+
def initialize(statement,code,title,filename,statement_number,context)
|
5
|
+
@statement,@code,@title,@statement_number,@context = statement,code,title,statement_number,context
|
6
|
+
@filename = File.basename(filename,'.*')
|
7
|
+
@statement.freeze; @filename.freeze; @statement_number.freeze
|
8
|
+
syntax_check
|
9
|
+
@regexp = nil
|
10
|
+
set_acceptance_code
|
11
|
+
@code.freeze; @title.freeze; @regexp.freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
def type = @code[0]
|
15
|
+
def to_s = @statement
|
16
|
+
def to_str = @statement
|
17
|
+
def match?(statement) = @regexp.match?(statement)
|
18
|
+
def scan(regex, &blk) = @statement.scan(regex, &blk)
|
19
|
+
def pattern? = !@regexp.nil?
|
20
|
+
def literal_regexp? = @statement[0]=='/' && @statement[-1]=='/'
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def syntax_check
|
25
|
+
@context.syntax.each do |rule|
|
26
|
+
raise Error, "syntax: #{rule}" unless @statement.instance_eval(rule)
|
27
|
+
rescue # other than Korekto::Error < Exception
|
28
|
+
raise Error, "#{$!.class}: #{rule}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_acceptance_code
|
33
|
+
case @code[0] # type
|
34
|
+
when 'P'
|
35
|
+
postulate
|
36
|
+
when 'D'
|
37
|
+
definition
|
38
|
+
when 'C'
|
39
|
+
conclusion
|
40
|
+
when 'X'
|
41
|
+
instantiation
|
42
|
+
when 'R'
|
43
|
+
result
|
44
|
+
when 'S'
|
45
|
+
set
|
46
|
+
when 'T'
|
47
|
+
tautology
|
48
|
+
when 'A', 'L'
|
49
|
+
# Axiom=>Tautoloty, Let=>Set,
|
50
|
+
pattern_type(0)
|
51
|
+
when 'M', 'E'
|
52
|
+
# Map=>Result, Existential=>Instantiation(X)
|
53
|
+
pattern_type(1)
|
54
|
+
when 'I'
|
55
|
+
# Inference=>Conclusion
|
56
|
+
pattern_type(2)
|
57
|
+
when 'W'
|
58
|
+
['T','S','R','X','C'].any? do |code|
|
59
|
+
begin
|
60
|
+
@code[0]=code
|
61
|
+
set_acceptance_code
|
62
|
+
true
|
63
|
+
rescue Error
|
64
|
+
false
|
65
|
+
end
|
66
|
+
end or raise Error, 'did not match any statement pattern'
|
67
|
+
else
|
68
|
+
raise Error, "statement type #{@code[0]} not implemented"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Common helper
|
73
|
+
|
74
|
+
def set_statement(support=nil, title=nil)
|
75
|
+
@code = "#{@code[0]}#{@statement_number}"
|
76
|
+
@code += "/#{support}" if support
|
77
|
+
@title = title.split(':',2).first if title
|
78
|
+
end
|
79
|
+
|
80
|
+
def support(*s)
|
81
|
+
support = []
|
82
|
+
s.each do |s|
|
83
|
+
c = s.code.split('/',2)[0]
|
84
|
+
c = s.filename+'.'+c unless s.filename=='-'
|
85
|
+
support.push(c)
|
86
|
+
end
|
87
|
+
return support.join(',')
|
88
|
+
end
|
89
|
+
|
90
|
+
# Pattern helpers
|
91
|
+
|
92
|
+
def newlines_count(n)
|
93
|
+
raise Error, "expected #{n} newlines" unless n==@regexp.inspect.gsub('\\\\','').scan('\\n').length
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_regexp
|
97
|
+
@regexp = @context.symbols.s2r(@statement)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Searches
|
101
|
+
|
102
|
+
def detect_statement(type)
|
103
|
+
statement = @context.type(type).detect do |statement|
|
104
|
+
statement.match? @statement
|
105
|
+
end
|
106
|
+
raise Error, "does not match any '#{type}' statement" unless statement
|
107
|
+
return statement
|
108
|
+
end
|
109
|
+
|
110
|
+
def heap_combos_search(type)
|
111
|
+
@context.heap.combos do |s1, s2|
|
112
|
+
compound = [s1,s2,@statement].join("\n")
|
113
|
+
@context.type(type).each do |inference|
|
114
|
+
return inference,s1,s2 if inference.match?(compound)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
raise Error, "does not match any '#{type}' statement"
|
118
|
+
end
|
119
|
+
|
120
|
+
def heap_search(type)
|
121
|
+
@context.heap.each do |s1|
|
122
|
+
compound = [s1,@statement].join("\n")
|
123
|
+
@context.type(type).each do |s0|
|
124
|
+
return s0,s1 if s0.match?(compound)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
raise Error, "does not match any '#{type}' statement"
|
128
|
+
end
|
129
|
+
|
130
|
+
# Defined/Undefined
|
131
|
+
|
132
|
+
def expected_instantiations(title=nil, n:nil)
|
133
|
+
undefined = @context.symbols.undefined(self)
|
134
|
+
if n ||= title&.match(/[1-9]\d*/)&.to_s&.to_i
|
135
|
+
raise Error, "expected #{n} undefined: #{undefined.join(' ')}" unless n==undefined.length
|
136
|
+
else
|
137
|
+
raise Error, 'nothing was undefined' if undefined.empty?
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def undefined_in_pattern
|
142
|
+
@title = @title.split(':',2).first if @title
|
143
|
+
undefined = @context.symbols.undefined(self)
|
144
|
+
@title = "#{@title}: #{undefined.join(' ')}" unless undefined.empty?
|
145
|
+
end
|
146
|
+
|
147
|
+
# Statement type processing
|
148
|
+
|
149
|
+
def pattern_type(nl)
|
150
|
+
set_regexp
|
151
|
+
newlines_count(nl)
|
152
|
+
undefined_in_pattern
|
153
|
+
set_statement
|
154
|
+
end
|
155
|
+
|
156
|
+
def tautology
|
157
|
+
expected_instantiations(n:0)
|
158
|
+
axiom = detect_statement('A')
|
159
|
+
set_statement(support(axiom), axiom.title)
|
160
|
+
end
|
161
|
+
|
162
|
+
def set
|
163
|
+
let = detect_statement('L')
|
164
|
+
expected_instantiations(let.title)
|
165
|
+
set_statement(support(let), let.title)
|
166
|
+
end
|
167
|
+
|
168
|
+
def result
|
169
|
+
expected_instantiations(n:0)
|
170
|
+
mapping,s1 = heap_search('M')
|
171
|
+
set_statement(support(mapping,s1), mapping.title)
|
172
|
+
end
|
173
|
+
|
174
|
+
def instantiation
|
175
|
+
existential,s1 = heap_search('E')
|
176
|
+
expected_instantiations(existential.title)
|
177
|
+
set_statement(support(existential,s1), existential.title)
|
178
|
+
end
|
179
|
+
|
180
|
+
def conclusion
|
181
|
+
expected_instantiations(n:0)
|
182
|
+
inference,s1,s2 = heap_combos_search('I')
|
183
|
+
set_statement(support(inference,s1,s2), inference.title)
|
184
|
+
end
|
185
|
+
|
186
|
+
def definition
|
187
|
+
expected_instantiations(@title)
|
188
|
+
set_statement
|
189
|
+
end
|
190
|
+
|
191
|
+
def postulate
|
192
|
+
expected_instantiations(n:0)
|
193
|
+
set_statement
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Korekto
|
2
|
+
class Statements
|
3
|
+
attr_reader :heap,:symbols,:syntax
|
4
|
+
def initialize
|
5
|
+
@statements = []
|
6
|
+
@heap = Heap.new(13)
|
7
|
+
@symbols = Symbols.new
|
8
|
+
@syntax = Syntax.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def type(c) = @statements.select{_1.type==c}
|
12
|
+
def length = @statements.length
|
13
|
+
|
14
|
+
def add(statement,code,title,filename,statement_number)
|
15
|
+
c = code[0]; w = c=='W'
|
16
|
+
if restatement = @statements.detect{(w or _1.type==c) and _1.to_s==statement}
|
17
|
+
case restatement.type
|
18
|
+
when 'D','X','S','P','T','C','R'
|
19
|
+
@heap.add restatement
|
20
|
+
else
|
21
|
+
raise Error, "restatement: #{restatement.code}"
|
22
|
+
end
|
23
|
+
code,_ = restatement.code
|
24
|
+
title ||= restatement.title
|
25
|
+
return code, title
|
26
|
+
end
|
27
|
+
statement = Statement.new(statement,code,title,filename,statement_number,self)
|
28
|
+
@statements.push statement
|
29
|
+
case statement.type
|
30
|
+
when 'A','I','E','M','L'
|
31
|
+
@symbols.define! statement
|
32
|
+
when 'D','X','S'
|
33
|
+
@symbols.define! statement
|
34
|
+
@heap.add statement
|
35
|
+
when 'P','T','C','R'
|
36
|
+
@heap.add statement
|
37
|
+
end
|
38
|
+
return statement.code, statement.title
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Korekto
|
2
|
+
class Symbols
|
3
|
+
attr_reader :t2p, :v2t
|
4
|
+
def initialize
|
5
|
+
@h = {}
|
6
|
+
@t2p = {}
|
7
|
+
@v2t = {}
|
8
|
+
@scanner = /:\w+|./
|
9
|
+
end
|
10
|
+
|
11
|
+
def set_scanner(value) = @scanner=Regexp.new(value)
|
12
|
+
|
13
|
+
def undefined(statement)
|
14
|
+
undefined = []
|
15
|
+
if statement.pattern?
|
16
|
+
unless statement.literal_regexp?
|
17
|
+
statement.scan(@scanner){|w| undefined.push(w) unless @v2t.include?(w) or @h.include?(w)}
|
18
|
+
end
|
19
|
+
else
|
20
|
+
statement.scan(@scanner){|w| undefined.push(w) unless @h.include?(w)}
|
21
|
+
end
|
22
|
+
return undefined.uniq
|
23
|
+
end
|
24
|
+
|
25
|
+
def define!(statement)
|
26
|
+
if statement.pattern?
|
27
|
+
unless statement.literal_regexp?
|
28
|
+
statement.scan(@scanner){|w| @h[w]=nil unless @v2t.include?(w) or @h.include?(w)}
|
29
|
+
end
|
30
|
+
else
|
31
|
+
statement.scan(@scanner){|w| @h[w]=nil unless @h.include?(w)}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def s2r(statement)
|
36
|
+
if statement[0]=='/' and statement[-1]=='/'
|
37
|
+
Regexp.new(statement[1..-2])
|
38
|
+
else
|
39
|
+
pattern,count,seen = '^',0,{}
|
40
|
+
Regexp.quote(statement).scan(@scanner) do |v|
|
41
|
+
if n=seen[v]
|
42
|
+
pattern << '\\'+n
|
43
|
+
elsif type = @v2t[v]
|
44
|
+
regex = @t2p[type]
|
45
|
+
if regex=='\n'
|
46
|
+
pattern << regex
|
47
|
+
else
|
48
|
+
count += 1
|
49
|
+
seen[v]=count.to_s
|
50
|
+
pattern << '('+regex+')'
|
51
|
+
end
|
52
|
+
else
|
53
|
+
# To avoid collisions with back-references,
|
54
|
+
# isolate digit in square brackets:
|
55
|
+
'0123456789'.include?(_=v[0]) and v[0]='['+_+']'
|
56
|
+
pattern << v
|
57
|
+
end
|
58
|
+
end
|
59
|
+
raise Error, 'pattern with no captures' if count < 1
|
60
|
+
pattern << '$'
|
61
|
+
Regexp.new(pattern)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Korekto
|
2
|
+
class Syntax
|
3
|
+
def initialize = @a=[]
|
4
|
+
def each = @a.each{|s| yield s}
|
5
|
+
|
6
|
+
def push(s)
|
7
|
+
# ensure it'll eval on string and returns boolean
|
8
|
+
b = ''.instance_eval(s)
|
9
|
+
raise Error, 'syntax rule must eval boolean' unless b==!!b
|
10
|
+
@a.push(s)
|
11
|
+
rescue
|
12
|
+
raise Error, "#{$!.class}: #{s}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
Neovim.plugin do |plug|
|
2
|
+
plug.command(:Korekto) do |nvim|
|
3
|
+
validations = nvim.command_output('w !korekto').strip.split("\n").map(&:strip)
|
4
|
+
msg = 'OK'
|
5
|
+
unless validations.empty?
|
6
|
+
buf = nvim.get_current_buf
|
7
|
+
while validation = validations.shift
|
8
|
+
fields = validation.split(':',4)
|
9
|
+
n = fields[1].to_i
|
10
|
+
if n > 0
|
11
|
+
fn,ln,code,title = fields
|
12
|
+
if code=='?' or code=='!'
|
13
|
+
# move onto error if on page
|
14
|
+
nvim.get_current_win.set_cursor([n,0]) if fn=='-'
|
15
|
+
# echo error message
|
16
|
+
msg = "#{fn}:#{ln}: #{title}"
|
17
|
+
# and stop.
|
18
|
+
break
|
19
|
+
elsif fn=='-'
|
20
|
+
line = buf[n].sub(/#.*$/,'').rstrip
|
21
|
+
line << "\t##{code}"
|
22
|
+
line << " #{title}" unless title==''
|
23
|
+
buf[n] = line unless line == buf[n]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
nvim.command "echom #{msg.inspect}"
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
autocmd BufRead,BufNewFile *.korekto set filetype=korekto
|
@@ -0,0 +1,12 @@
|
|
1
|
+
syntax match Comment /^\s*#.\+$/
|
2
|
+
syntax match Pass /\s#[A-Z][^#]*$/
|
3
|
+
syntax match Syntax /^[?] \w.\+$/
|
4
|
+
syntax match Patch /^::[A-Z]\w\+#\w\+[^=]\+=.\+$/
|
5
|
+
syntax match Import /^< [\/A-Za-z\_\-\.]\+$/
|
6
|
+
highlight Comment ctermfg=darkblue
|
7
|
+
highlight Pass ctermfg=darkgreen
|
8
|
+
highlight Syntax ctermfg=darkmagenta
|
9
|
+
highlight Patch ctermfg=darkgrey
|
10
|
+
highlight Import ctermfg=darkyellow
|
11
|
+
setlocal tabstop=23
|
12
|
+
map <F7> :Korekto<CR>
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: korekto
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.210306
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- carlosjhr64
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-03-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: help_parser
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '7.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 7.0.200907
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '7.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 7.0.200907
|
33
|
+
description: |
|
34
|
+
A general proof checker.
|
35
|
+
|
36
|
+
Works with neovim(nvim).
|
37
|
+
email: carlosjhr64@gmail.com
|
38
|
+
executables:
|
39
|
+
- korekto
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files: []
|
42
|
+
files:
|
43
|
+
- bin/korekto
|
44
|
+
- lib/korekto.rb
|
45
|
+
- lib/korekto/heap.rb
|
46
|
+
- lib/korekto/main.rb
|
47
|
+
- lib/korekto/statement.rb
|
48
|
+
- lib/korekto/statements.rb
|
49
|
+
- lib/korekto/symbols.rb
|
50
|
+
- lib/korekto/syntax.rb
|
51
|
+
- rplugin/ruby/korekto.rb
|
52
|
+
- start/korekto/ftdetect/korekto.vim
|
53
|
+
- start/korekto/syntax/korekto.vim
|
54
|
+
homepage: https://github.com/carlosjhr64/korekto
|
55
|
+
licenses:
|
56
|
+
- MIT
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements:
|
73
|
+
- 'ruby: ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-linux]'
|
74
|
+
- 'nvim: NVIM v0.4.4'
|
75
|
+
- 'xdg-open: xdg-open 1.1.3+'
|
76
|
+
rubygems_version: 3.2.3
|
77
|
+
signing_key:
|
78
|
+
specification_version: 4
|
79
|
+
summary: A general proof checker.
|
80
|
+
test_files: []
|