Skip to content

Instantly share code, notes, and snippets.

@PedroHLC
Last active April 5, 2019 03:46
Show Gist options
  • Save PedroHLC/ec13efc8a59488a262a529f361ab6f8b to your computer and use it in GitHub Desktop.
Save PedroHLC/ec13efc8a59488a262a529f361ab6f8b to your computer and use it in GitHub Desktop.
Small linter to check if student didn't used invalid operations
#!/usr/bin/env ruby
def cat(fname)
data = (fname == '-' ? STDIN.read : File.open(fname, 'rb').read)
return data.force_encoding('UTF-8')
end
class CodeToken < String
attr_reader :match_pos
attr_accessor :kind
def initialize (value, pos)
super(value)
@kind = nil
@match_pos = pos
end
end
class St
def self.or(array)
return nil
end
def self.sq(array)
return nil
end
def self.mb(x)
return nil
end
def self.vr(start, repeat, _end)
return nil
end
end
module BSV
KEYWORDS = ['let', 'function', 'endfunction',
'import', 'typedef', 'return']
TOKENS = {
:A_COMMENT_SINGLE => '(\/\/[^\n]*)',
:A_COMMENT_MULTI => '(\/\*(?!\*\/).*\*\/)',
:B_STRING => '("(?:\\\"|[^\n"])*")',
:C_NAMESPACE => '([\w\_]+(?:\:\:[\w\_]+)*\:\:[\w\_\*])',
:C_ENDOP => '(;)',
:C_SPLIT => '(,)',
:C_ENDPARAM => '(\))',
:C_PROVISOS => '(provisos\s+\()',
:D_ASSOC => '((?:\:\:)?\=)',
:D_KEYWORDS => '(?<![\w_])('+KEYWORDS.join('|')+')(?![\w_])',
:E_TYPE => '([A-Z][\w_]*(?:\#\()?)',
:F_FUNCTION => '(\w+\()',
:F_VARIABLE => '([a-z]\w*)',
:G_NUMBER => '(\d+(?:\'\w\d+)?)',
:X_DENY => '(\*|\+|\<\<|\>\>)',
:Z_CATCHALL => '(\S)+'
}
VALID_TYPE = nil
VALID_CALL = nil
VALID_VALUE = St.or([:G_NUMBER, :F_VARIABLE, VALID_CALL])
SENTENCES = St.or [
:A_COMMENT_SINGLE,
:A_COMMENT_MULTI,
St.sq(['import', :C_NAMESPACE, :C_ENDOP]),
St.sq([St.mb(St.or(['let', VALID_TYPE])),
:F_VARIABLE, :D_ASSOC,
VALID_VALUE,
:C_ENDOP
]),
St.sq(['typedef', VALID_TYPE, :E_TYPE, :C_ENDOP]),
St.sq(['function', :E_TYPE, :F_FUNCTION,
St.vr(St.sq([VALID_TYPE, :F_VARIABLE]), :C_SPLIT, :C_ENDPARAM),
St.mb(St.sq([:C_PROVISOS, St.vr(VALID_TYPE, :C_SPLIT, :C_ENDPARAM)])),
:C_ENDOP
]),
St.sq(['return', VALID_VALUE]),
St.sq(['endfunction'])
]
def self.tokenize(buffer)
regex = Regexp.new(TOKENS.values.join('|'),
Regexp::MULTILINE | Regexp::FIXEDENCODING)
organize = lambda do |match|
return CodeToken.new(match,
Regexp.last_match.offset(0).first)
end
action = lambda do |res|
item_i = res.find_index { |x| !x.nil? }
item = res[item_i]
token = organize.call(item)
token.kind = TOKENS.keys[item_i]
return token
end
return (buffer.scan(regex).map(&action))
end
def self.validate(tokens)
tokens.each do |item|
#puts "#{item.kind}: #{item}"
return false if
item.kind == :X_DENY or
item.kind == :Z_CATCHALL
end
return true
end
end
def main()
if ARGV[0].nil? or ($in_fname = ARGV[0].to_s).size < 1
puts 'Invalid filename. Use \'-\' for stdin.'
return -1
end
k = BSV.validate(BSV.tokenize(cat $in_fname))
puts 'Código '+(k ? '' : 'in')+'válido'
end
main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment