File Manager
class RBS::Parser
token tUIDENT tLIDENT tNAMESPACE tINTERFACEIDENT tGLOBALIDENT
tLKEYWORD tUKEYWORD tLKEYWORD_Q_E tUKEYWORD_Q_E
tIVAR tCLASSVAR
tANNOTATION
tSTRING tSYMBOL tINTEGER tWRITE_ATTR
kLPAREN kRPAREN kLBRACKET kRBRACKET kLBRACE kRBRACE
kVOID kNIL kTRUE kFALSE kANY kUNTYPED kTOP kBOT kSELF kSELFQ kINSTANCE kCLASS kBOOL kSINGLETON kTYPE kDEF kMODULE
kPRIVATE kPUBLIC kALIAS
kCOLON kCOLON2 kCOMMA kBAR kAMP kHAT kARROW kQUESTION kEXCLAMATION kSTAR kSTAR2 kFATARROW kEQ kDOT kDOT3 kLT
kINTERFACE kEND kINCLUDE kEXTEND kATTRREADER kATTRWRITER kATTRACCESSOR tOPERATOR tQUOTEDMETHOD tQUOTEDIDENT
kPREPEND kEXTENSION kINCOMPATIBLE
type_TYPE type_SIGNATURE type_METHODTYPE tEOF
kOUT kIN kUNCHECKED kOVERLOAD
prechigh
nonassoc kQUESTION
left kAMP
left kBAR
nonassoc kARROW
preclow
expect 5
rule
target:
type_TYPE type eof {
result = val[1]
}
| type_SIGNATURE signatures eof {
result = val[1]
}
| type_METHODTYPE method_type eof {
result = val[1]
}
eof: | tEOF
signatures:
{ result = [] }
| signatures signature {
result = val[0].push(val[1])
}
signature:
type_decl
| const_decl
| global_decl
| interface_decl
| module_decl
| class_decl
start_new_scope: { start_new_variables_scope }
start_merged_scope: { start_merged_variables_scope }
annotations:
{ result = [] }
| tANNOTATION annotations {
result = val[1].unshift(Annotation.new(string: val[0].value, location: val[0].location))
}
class_decl:
annotations kCLASS start_new_scope class_name module_type_params super_class class_members kEND {
reset_variable_scope
location = val[1].location + val[7].location
result = Declarations::Class.new(
name: val[3].value,
type_params: val[4]&.value || Declarations::ModuleTypeParams.empty,
super_class: val[5],
members: val[6],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location)
)
}
super_class:
{ result = nil }
| kLT class_name {
result = Declarations::Class::Super.new(name: val[1].value,
args: [],
location: val[1].location)
}
| kLT class_name kLBRACKET type_list kRBRACKET {
result = Declarations::Class::Super.new(name: val[1].value,
args: val[3],
location: val[1].location + val[4].location)
}
module_decl:
annotations kMODULE start_new_scope class_name module_type_params colon_module_self_types class_members kEND {
reset_variable_scope
location = val[1].location + val[7].location
result = Declarations::Module.new(
name: val[3].value,
type_params: val[4]&.value || Declarations::ModuleTypeParams.empty,
self_types: val[5],
members: val[6],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location)
)
}
| annotations kMODULE start_new_scope tUKEYWORD module_self_types class_members kEND {
reset_variable_scope
location = val[1].location + val[6].location
result = Declarations::Module.new(
name: val[3].value,
type_params: Declarations::ModuleTypeParams.empty,
self_types: val[4],
members: val[5],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location)
)
}
colon_module_self_types:
{ result = [] }
| kCOLON module_self_types {
result = val[1]
}
module_self_types:
module_self_type {
result = [val[0]]
}
| module_self_types kCOMMA module_self_type {
result = val[0].push(val[2])
}
module_self_type:
qualified_name kLBRACKET type_list kRBRACKET {
name = val[0].value
args = val[2]
location = val[0].location + val[3].location
case
when name.class?
result = Declarations::Module::Self.new(name: name, args: args, location: location)
when name.interface?
result = Declarations::Module::Self.new(name: name, args: args, location: location)
else
raise SemanticsError.new("Module self type should be instance or interface", subject: val[0], location: val[0].location)
end
}
| qualified_name {
name = val[0].value
args = []
location = val[0].location
case
when name.class?
result = Declarations::Module::Self.new(name: name, args: args, location: location)
when name.interface?
result = Declarations::Module::Self.new(name: name, args: args, location: location)
else
raise SemanticsError.new("Module self type should be instance or interface", subject: val[0], location: val[0].location)
end
}
class_members:
{ result = [] }
| class_members class_member {
result = val[0].push(val[1])
}
class_member:
method_member
| include_member
| extend_member
| prepend_member
| var_type_member
| attribute_member
| kPUBLIC {
result = Members::Public.new(location: val[0].location)
}
| kPRIVATE {
result = Members::Private.new(location: val[0].location)
}
| alias_member
| signature
attribute_kind:
{ result = :instance }
| kSELF kDOT { result = :singleton }
attribute_member:
annotations kATTRREADER attribute_kind keyword type {
location = val[1].location + val[4].location
result = Members::AttrReader.new(name: val[3].value,
ivar_name: nil,
type: val[4],
kind: val[2],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
| annotations kATTRREADER attribute_kind method_name attr_var_opt kCOLON type {
location = val[1].location + val[6].location
result = Members::AttrReader.new(name: val[3].value.to_sym,
ivar_name: val[4],
type: val[6],
kind: val[2],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
| annotations kATTRWRITER attribute_kind keyword type {
location = val[1].location + val[4].location
result = Members::AttrWriter.new(name: val[3].value,
ivar_name: nil,
kind: val[2],
type: val[4],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
| annotations kATTRWRITER attribute_kind method_name attr_var_opt kCOLON type {
location = val[1].location + val[6].location
result = Members::AttrWriter.new(name: val[3].value.to_sym,
ivar_name: val[4],
kind: val[2],
type: val[6],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
| annotations kATTRACCESSOR attribute_kind keyword type {
location = val[1].location + val[4].location
result = Members::AttrAccessor.new(name: val[3].value,
ivar_name: nil,
kind: val[2],
type: val[4],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
| annotations kATTRACCESSOR attribute_kind method_name attr_var_opt kCOLON type {
location = val[1].location + val[6].location
result = Members::AttrAccessor.new(name: val[3].value.to_sym,
ivar_name: val[4],
kind: val[2],
type: val[6],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
attr_var_opt:
{ result = nil }
| kLPAREN kRPAREN { result = false }
| kLPAREN tIVAR kRPAREN { result = val[1].value }
var_type_member:
tIVAR kCOLON type {
location = val[0].location + val[2].location
result = Members::InstanceVariable.new(
name: val[0].value,
type: val[2],
location: location,
comment: leading_comment(location)
)
}
| tCLASSVAR kCOLON type {
type = val[2]
if type.is_a?(Types::Variable)
type = Types::ClassInstance.new(
name: TypeName.new(name: type.name, namespace: Namespace.empty),
args: [],
location: type.location
)
end
location = val[0].location + val[2].location
result = Members::ClassVariable.new(
name: val[0].value,
type: type,
location: location,
comment: leading_comment(location)
)
}
| kSELF kDOT tIVAR kCOLON type {
type = val[4]
if type.is_a?(Types::Variable)
type = Types::ClassInstance.new(
name: TypeName.new(name: type.name, namespace: Namespace.empty),
args: [],
location: type.location
)
end
location = val[0].location + val[4].location
result = Members::ClassInstanceVariable.new(
name: val[2].value,
type: type,
location: location,
comment: leading_comment(location)
)
}
interface_decl:
annotations kINTERFACE start_new_scope interface_name module_type_params interface_members kEND {
reset_variable_scope
location = val[1].location + val[6].location
result = Declarations::Interface.new(
name: val[3].value,
type_params: val[4]&.value || Declarations::ModuleTypeParams.empty,
members: val[5],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location)
)
}
interface_members:
{ result = [] }
| interface_members interface_member {
result = val[0].push(val[1])
}
interface_member:
method_member {
unless val[0].kind == :instance
raise SemanticsError.new("Interface cannot have singleton method", subject: val[0], location: val[0].location)
end
if val[0].types.last == :super
raise SemanticsError.new("Interface method cannot have `super` type", subject: val[0], location: val[0].location)
end
result = val[0]
}
| include_member {
unless val[0].name.interface?
raise SemanticsError.new("Interface should include an interface", subject: val[0], location: val[0].location)
end
result = val[0]
}
| alias_member
include_member:
annotations kINCLUDE qualified_name {
if val[2].value.alias?
raise SemanticsError.new("Should include module or interface", subject: val[2].value, location: val[2].location)
end
location = val[1].location + val[2].location
result = Members::Include.new(name: val[2].value,
args: [],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
| annotations kINCLUDE qualified_name kLBRACKET type_list kRBRACKET {
if val[2].value.alias?
raise SemanticsError.new("Should include module or interface", subject: val[2].value, location: val[2].location)
end
location = val[1].location + val[5].location
result = Members::Include.new(name: val[2].value,
args: val[4],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
extend_member:
annotations kEXTEND qualified_name {
if val[2].value.alias?
raise SemanticsError.new("Should extend module or interface", subject: val[2].value, location: val[2].location)
end
location = val[1].location + val[2].location
result = Members::Extend.new(name: val[2].value,
args: [],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
| annotations kEXTEND qualified_name kLBRACKET type_list kRBRACKET {
if val[2].value.alias?
raise SemanticsError.new("Should extend module or interface", subject: val[2].value, location: val[2].location)
end
location = val[1].location + val[5].location
result = Members::Extend.new(name: val[2].value,
args: val[4],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
prepend_member:
annotations kPREPEND qualified_name {
unless val[2].value.class?
raise SemanticsError.new("Should prepend module", subject: val[2].value, location: val[2].location)
end
location = val[1].location + val[2].location
result = Members::Prepend.new(name: val[2].value,
args: [],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
| annotations kPREPEND qualified_name kLBRACKET type_list kRBRACKET {
unless val[2].value.class?
raise SemanticsError.new("Should prepend module", subject: val[2].value, location: val[2].location)
end
location = val[1].location + val[5].location
result = Members::Prepend.new(name: val[2].value,
args: val[4],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
overload:
{ result = nil }
| kOVERLOAD {
RBS.logger.warn "`overload def` syntax is deprecated. Use `...` syntax instead."
result = val[0]
}
method_member:
annotations attributes overload kDEF method_kind def_name method_types {
location = val[3].location + val[6].last.location
last_type = val[6].last
if last_type.is_a?(LocatedValue) && last_type.value == :dot3
overload = true
val[6].pop
else
overload = false
end
result = Members::MethodDefinition.new(
name: val[5].value,
kind: val[4],
types: val[6],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || val[2]&.location || val[3].location),
overload: overload || !!val[2]
)
}
attributes:
| attributes kINCOMPATIBLE {
RBS.logger.warn "`incompatible` method attribute is deprecated and ignored."
}
method_kind:
{ result = :instance }
| kSELF kDOT { result = :singleton }
| kSELFQ kDOT { result = :singleton_instance }
method_types:
method_type { result = [val[0]] }
| kDOT3 { result = [LocatedValue.new(value: :dot3, location: val[0].location)] }
| method_type kBAR method_types {
result = val[2].unshift(val[0])
}
method_type:
start_merged_scope type_params proc_type {
reset_variable_scope
location = (val[1] || val[2]).location + val[2].location
type_params = val[1]&.value || []
type, block = val[2].value
result = MethodType.new(type_params: type_params,
type: type,
block: block,
location: location)
}
params_opt:
{ result = nil }
| kLPAREN params kRPAREN {
result = LocatedValue.new(value: val[1], location: val[0].location + val[2].location)
}
block:
kLBRACE simple_function_type kRBRACE {
block = Types::Block.new(type: val[1].value, required: true)
result = LocatedValue.new(value: block, location: val[0].location + val[2].location)
}
| kQUESTION kLBRACE simple_function_type kRBRACE {
block = Types::Block.new(type: val[2].value, required: false)
result = LocatedValue.new(value: block, location: val[0].location + val[3].location)
}
def_name:
keyword
| method_name kCOLON {
result = LocatedValue.new(value: val[0].value.to_sym,
location: val[0].location + val[1].location)
}
method_name:
tOPERATOR
| kAMP | kHAT | kSTAR | kLT | kEXCLAMATION | kSTAR2 | kBAR
| method_name0
| method_name0 kQUESTION {
unless val[0].location.pred?(val[1].location)
raise SyntaxError.new(token_str: "kQUESTION", error_value: val[1])
end
result = LocatedValue.new(value: "#{val[0].value}?",
location: val[0].location + val[1].location)
}
| method_name0 kEXCLAMATION {
unless val[0].location.pred?(val[1].location)
raise SyntaxError.new(token_str: "kEXCLAMATION", error_value: val[1])
end
result = LocatedValue.new(value: "#{val[0].value}!",
location: val[0].location + val[1].location)
}
| tQUOTEDMETHOD
| tQUOTEDIDENT
| tWRITE_ATTR
method_name0: tUIDENT | tLIDENT | tINTERFACEIDENT | identifier_keywords
identifier_keywords:
kCLASS | kVOID | kNIL | kTRUE | kFALSE | kANY | kUNTYPED | kTOP | kBOT | kINSTANCE | kBOOL | kSINGLETON
| kTYPE | kMODULE | kPRIVATE | kPUBLIC | kEND | kINCLUDE | kEXTEND | kPREPEND
| kATTRREADER | kATTRACCESSOR | kATTRWRITER | kDEF | kEXTENSION | kSELF | kINCOMPATIBLE
| kUNCHECKED | kINTERFACE | kALIAS | kOUT | kIN | kOVERLOAD
module_type_params:
{ result = nil }
| kLBRACKET module_type_params0 kRBRACKET {
val[1].each {|p| insert_bound_variable(p.name) }
result = LocatedValue.new(value: val[1], location: val[0].location + val[2].location)
}
module_type_params0:
module_type_param {
result = Declarations::ModuleTypeParams.new()
result.add(val[0])
}
| module_type_params0 kCOMMA module_type_param {
result = val[0].add(val[2])
}
module_type_param:
type_param_check type_param_variance tUIDENT {
result = Declarations::ModuleTypeParams::TypeParam.new(name: val[2].value.to_sym,
variance: val[1],
skip_validation: val[0])
}
type_param_variance:
{ result = :invariant }
| kOUT { result = :covariant }
| kIN { result = :contravariant }
type_param_check:
{ result = false }
| kUNCHECKED { result = true }
type_params:
{ result = nil }
| kLBRACKET type_params0 kRBRACKET {
val[1].each {|var| insert_bound_variable(var) }
result = LocatedValue.new(value: val[1],
location: val[0].location + val[2].location)
}
type_params0:
tUIDENT {
result = [val[0].value.to_sym]
}
| type_params0 kCOMMA tUIDENT {
result = val[0].push(val[2].value.to_sym)
}
alias_member:
annotations kALIAS method_name method_name {
location = val[1].location + val[3].location
result = Members::Alias.new(
new_name: val[2].value.to_sym,
old_name: val[3].value.to_sym,
kind: :instance,
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location)
)
}
| annotations kALIAS kSELF kDOT method_name kSELF kDOT method_name {
location = val[1].location + val[7].location
result = Members::Alias.new(
new_name: val[4].value.to_sym,
old_name: val[7].value.to_sym,
kind: :singleton,
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location)
)
}
type_decl:
annotations kTYPE type_alias_name kEQ type {
location = val[1].location + val[4].location
result = Declarations::Alias.new(name: val[2].value,
type: val[4],
annotations: val[0],
location: location,
comment: leading_comment(val[0].first&.location || location))
}
const_decl:
class_name kCOLON type {
location = val[0].location + val[2].location
result = Declarations::Constant.new(name: val[0].value,
type: val[2],
location: location,
comment: leading_comment(location))
}
| namespace tUKEYWORD type {
location = (val[0] || val[1]).location + val[2].location
name = TypeName.new(name: val[1].value, namespace: val[0]&.value || Namespace.empty)
result = Declarations::Constant.new(name: name,
type: val[2],
location: location,
comment: leading_comment(location))
}
global_decl:
tGLOBALIDENT kCOLON type {
location = val[0].location + val[2].location
result = Declarations::Global.new(name: val[0].value.to_sym,
type: val[2],
location: location,
comment: leading_comment(location))
}
type:
simple_type
| type kBAR type {
types = case l = val[0]
when Types::Union
l.types + [val[2]]
else
[l, val[2]]
end
result = Types::Union.new(types: types, location: val[0].location + val[2].location)
}
| type kAMP type {
types = case l = val[0]
when Types::Intersection
l.types + [val[2]]
else
[l, val[2]]
end
result = Types::Intersection.new(types: types,
location: val[0].location + val[2].location)
}
simple_type:
kVOID {
result = Types::Bases::Void.new(location: val[0].location)
}
| kANY {
RBS.logger.warn "`any` type is deprecated. Use `untyped` instead. (#{val[0].location.to_s})"
result = Types::Bases::Any.new(location: val[0].location)
}
| kUNTYPED {
result = Types::Bases::Any.new(location: val[0].location)
}
| kBOOL {
result = Types::Bases::Bool.new(location: val[0].location)
}
| kNIL {
result = Types::Bases::Nil.new(location: val[0].location)
}
| kTOP {
result = Types::Bases::Top.new(location: val[0].location)
}
| kBOT {
result = Types::Bases::Bottom.new(location: val[0].location)
}
| kSELF {
result = Types::Bases::Self.new(location: val[0].location)
}
| kSELFQ {
result = Types::Optional.new(type: Types::Bases::Self.new(location: val[0].location),
location: val[0].location)
}
| kINSTANCE {
result = Types::Bases::Instance.new(location: val[0].location)
}
| kCLASS {
result = Types::Bases::Class.new(location: val[0].location)
}
| kTRUE {
result = Types::Literal.new(literal: true, location: val[0].location)
}
| kFALSE {
result = Types::Literal.new(literal: false, location: val[0].location)
}
| tINTEGER {
result = Types::Literal.new(literal: val[0].value, location: val[0].location)
}
| tSTRING {
result = Types::Literal.new(literal: val[0].value, location: val[0].location)
}
| tSYMBOL {
result = Types::Literal.new(literal: val[0].value, location: val[0].location)
}
| qualified_name {
name = val[0].value
args = []
location = val[0].location
case
when name.class?
if is_bound_variable?(name.name)
result = Types::Variable.new(name: name.name, location: location)
else
result = Types::ClassInstance.new(name: name, args: args, location: location)
end
when name.alias?
result = Types::Alias.new(name: name, location: location)
when name.interface?
result = Types::Interface.new(name: name, args: args, location: location)
end
}
| qualified_name kLBRACKET type_list kRBRACKET {
name = val[0].value
args = val[2]
location = val[0].location + val[3].location
case
when name.class?
if is_bound_variable?(name.name)
raise SemanticsError.new("#{name.name} is type variable and cannot be applied", subject: name, location: location)
end
result = Types::ClassInstance.new(name: name, args: args, location: location)
when name.interface?
result = Types::Interface.new(name: name, args: args, location: location)
else
raise SyntaxError.new(token_str: "kLBRACKET", error_value: val[1])
end
}
| kLBRACKET kRBRACKET {
location = val[0].location + val[1].location
result = Types::Tuple.new(types: [], location: location)
}
| kLBRACKET type_list kRBRACKET {
location = val[0].location + val[2].location
types = val[1]
result = Types::Tuple.new(types: types, location: location)
}
| kLPAREN type kRPAREN {
type = val[1].dup
type.instance_eval do
@location = val[0].location + val[2].location
end
result = type
}
| kSINGLETON kLPAREN class_name kRPAREN {
result = Types::ClassSingleton.new(name: val[2].value,
location: val[0].location + val[3].location)
}
| kHAT proc_type {
type, block = val[1].value
result = Types::Proc.new(type: type, block: block, location: val[0].location + val[1].location)
}
| simple_type kQUESTION {
result = Types::Optional.new(type: val[0], location: val[0].location + val[1].location)
}
| record_type
type_list:
type {
result = [val[0]]
}
| type_list kCOMMA type {
result = val[0] + [val[2]]
}
record_type:
kLBRACE record_fields kRBRACE {
result = Types::Record.new(
fields: val[1],
location: val[0].location + val[2].location
)
}
record_fields:
record_field {
result = val[0]
}
| record_field kCOMMA record_fields {
result = val[0].merge!(val[2])
}
record_field:
tSYMBOL kFATARROW type {
result = { val[0].value => val[2] }
}
| tSTRING kFATARROW type {
result = { val[0].value => val[2] }
}
| tINTEGER kFATARROW type {
result = { val[0].value => val[2] }
}
| keyword type {
result = { val[0].value => val[1] }
}
| identifier_keywords kCOLON type {
result = { val[0].value => val[2] }
}
| tQUOTEDIDENT kCOLON type {
result = { val[0].value => val[2] }
}
| tQUOTEDMETHOD kCOLON type {
result = { val[0].value => val[2] }
}
keyword_name:
keyword
| identifier_keywords kCOLON {
result = val[0]
}
keyword: tLKEYWORD | tUKEYWORD | tLKEYWORD_Q_E | tUKEYWORD_Q_E
proc_type:
params_opt block kARROW simple_type {
location = (val[0] || val[1] || val[2]).location + val[3].location
params = val[0]&.value || [[], [], nil, [], {}, {}, nil]
type = Types::Function.new(
required_positionals: params[0],
optional_positionals: params[1],
rest_positionals: params[2],
trailing_positionals: params[3],
required_keywords: params[4],
optional_keywords: params[5],
rest_keywords: params[6],
return_type: val[3]
)
block = val[1].value
result = LocatedValue.new(value: [type, block], location: location)
}
| simple_function_type {
result = LocatedValue.new(value: [val[0].value, nil], location: val[0].location)
}
simple_function_type:
kLPAREN params kRPAREN kARROW simple_type {
location = val[0].location + val[4].location
type = Types::Function.new(
required_positionals: val[1][0],
optional_positionals: val[1][1],
rest_positionals: val[1][2],
trailing_positionals: val[1][3],
required_keywords: val[1][4],
optional_keywords: val[1][5],
rest_keywords: val[1][6],
return_type: val[4],
)
result = LocatedValue.new(value: type, location: location)
}
| kARROW simple_type {
location = val[0].location + val[1].location
type = Types::Function.new(
required_positionals: [],
optional_positionals: [],
rest_positionals: nil,
trailing_positionals: [],
required_keywords: {},
optional_keywords: {},
rest_keywords: nil,
return_type: val[1]
)
result = LocatedValue.new(value: type, location: location)
}
params:
required_positional kCOMMA params {
result = val[2]
result[0].unshift(val[0])
}
| required_positional {
result = empty_params_result
result[0].unshift(val[0])
}
| optional_positional_params
optional_positional_params:
optional_positional kCOMMA optional_positional_params {
result = val[2]
result[1].unshift(val[0])
}
| optional_positional {
result = empty_params_result
result[1].unshift(val[0])
}
| rest_positional_param
rest_positional_param:
rest_positional kCOMMA trailing_positional_params {
result = val[2]
result[2] = val[0]
}
| rest_positional {
result = empty_params_result
result[2] = val[0]
}
| trailing_positional_params
trailing_positional_params:
required_positional kCOMMA trailing_positional_params {
result = val[2]
result[3].unshift(val[0])
}
| required_positional {
result = empty_params_result
result[3].unshift(val[0])
}
| keyword_params
keyword_params:
{
result = empty_params_result
}
| required_keyword kCOMMA keyword_params {
result = val[2]
result[4].merge!(val[0])
}
| required_keyword {
result = empty_params_result
result[4].merge!(val[0])
}
| optional_keyword kCOMMA keyword_params {
result = val[2]
result[5].merge!(val[0])
}
| optional_keyword {
result = empty_params_result
result[5].merge!(val[0])
}
| rest_keyword {
result = empty_params_result
result[6] = val[0]
}
required_positional:
type var_name_opt {
result = Types::Function::Param.new(type: val[0],
name: val[1]&.value&.to_sym)
}
optional_positional:
kQUESTION type var_name_opt {
result = Types::Function::Param.new(type: val[1],
name: val[2]&.value&.to_sym)
}
rest_positional:
kSTAR type var_name_opt {
result = Types::Function::Param.new(type: val[1],
name: val[2]&.value&.to_sym)
}
required_keyword:
keyword_name type var_name_opt {
param = Types::Function::Param.new(type: val[1],
name: val[2]&.value&.to_sym)
result = { val[0].value => param }
}
optional_keyword:
kQUESTION keyword_name type var_name_opt {
param = Types::Function::Param.new(type: val[2],
name: val[3]&.value&.to_sym)
result = { val[1].value => param }
}
rest_keyword:
kSTAR2 type var_name_opt {
result = Types::Function::Param.new(type: val[1],
name: val[2]&.value&.to_sym)
}
var_name_opt:
| tLIDENT | tINTERFACEIDENT | tQUOTEDIDENT
qualified_name:
namespace simple_name {
namespace = val[0]&.value || Namespace.empty
name = val[1].value.to_sym
type_name = TypeName.new(namespace: namespace, name: name)
location = (loc0 = val[0]&.location) ? loc0 + val[1].location : val[1].location
result = LocatedValue.new(value: type_name, location: location)
}
simple_name:
tUIDENT | tLIDENT | tINTERFACEIDENT
interface_name:
namespace tINTERFACEIDENT {
namespace = val[0]&.value || Namespace.empty
name = val[1].value.to_sym
type_name = TypeName.new(namespace: namespace, name: name)
location = (loc0 = val[0]&.location) ? loc0 + val[1].location : val[1].location
result = LocatedValue.new(value: type_name, location: location)
}
class_name:
namespace tUIDENT {
namespace = val[0]&.value || Namespace.empty
name = val[1].value.to_sym
type_name = TypeName.new(namespace: namespace, name: name)
location = (loc0 = val[0]&.location) ? loc0 + val[1].location : val[1].location
result = LocatedValue.new(value: type_name, location: location)
}
type_alias_name:
namespace tLIDENT {
namespace = val[0]&.value || Namespace.empty
name = val[1].value.to_sym
type_name = TypeName.new(namespace: namespace, name: name)
location = (loc0 = val[0]&.location) ? loc0 + val[1].location : val[1].location
result = LocatedValue.new(value: type_name, location: location)
}
namespace:
{
result = nil
}
| kCOLON2 {
result = LocatedValue.new(value: Namespace.root, location: val[0].location)
}
| kCOLON2 tNAMESPACE {
namespace = Namespace.parse(val[1].value).absolute!
result = LocatedValue.new(value: namespace, location: val[0].location + val[1].location)
}
| tNAMESPACE {
namespace = Namespace.parse(val[0].value)
result = LocatedValue.new(value: namespace, location: val[0].location)
}
end
---- inner
Types = RBS::Types
Namespace = RBS::Namespace
TypeName = RBS::TypeName
Declarations = RBS::AST::Declarations
Members = RBS::AST::Members
MethodType = RBS::MethodType
Annotation = RBS::AST::Annotation
class LocatedValue
attr_reader :location
attr_reader :value
def initialize(location:, value:)
@location = location
@value = value
end
end
require "strscan"
attr_reader :input
attr_reader :buffer
attr_reader :eof_re
def initialize(type, buffer:, eof_re:)
super()
@type = type
@buffer = buffer
@input = StringScanner.new(buffer.content)
@eof_re = eof_re
@eof = false
@bound_variables_stack = []
@comments = {}
@ascii_only = buffer.content.ascii_only?
end
def start_merged_variables_scope
set = @bound_variables_stack.last&.dup || Set.new
@bound_variables_stack.push set
end
def start_new_variables_scope
@bound_variables_stack.push Set.new
end
def reset_variable_scope
@bound_variables_stack.pop
end
def insert_bound_variable(var)
@bound_variables_stack.last << var
end
def is_bound_variable?(var)
(@bound_variables_stack.last || Set.new).member?(var)
end
def self.parse_signature(input, eof_re: nil)
case input
when RBS::Buffer
buffer = input
else
buffer = RBS::Buffer.new(name: nil, content: input.to_s)
end
self.new(:SIGNATURE, buffer: buffer, eof_re: eof_re).do_parse
end
def self.parse_type(input, variables: [], eof_re: nil)
case input
when RBS::Buffer
buffer = input
else
buffer = RBS::Buffer.new(name: nil, content: input.to_s)
end
self.new(:TYPE, buffer: buffer, eof_re: eof_re).yield_self do |parser|
parser.start_new_variables_scope
variables.each do |var|
parser.insert_bound_variable var
end
parser.do_parse
ensure
parser.reset_variable_scope
end
end
def self.parse_method_type(input, variables: [], eof_re: nil)
case input
when RBS::Buffer
buffer = input
else
buffer = RBS::Buffer.new(name: nil, content: input.to_s)
end
self.new(:METHODTYPE, buffer: buffer, eof_re: eof_re).yield_self do |parser|
parser.start_new_variables_scope
variables.each do |var|
parser.insert_bound_variable var
end
parser.do_parse
ensure
parser.reset_variable_scope
end
end
def leading_comment(location)
@comments[location.start_line-1]
end
def push_comment(string, location)
if (comment = leading_comment(location)) && comment.location.start_column == location.start_column
comment.concat(string: "#{string}\n", location: location)
@comments[comment.location.end_line] = comment
else
new_comment = AST::Comment.new(string: "#{string}\n", location: location)
@comments[new_comment.location.end_line] = new_comment
end
end
def new_token(type, value = input.matched)
charpos = charpos(input)
matched = input.matched
if matched
start_index = charpos - matched.size
end_index = charpos
location = RBS::Location.new(buffer: buffer,
start_pos: start_index,
end_pos: end_index)
[type, LocatedValue.new(location: location, value: value)]
else
# scanner hasn't matched yet
[false, nil]
end
end
def charpos(scanner)
if @ascii_only
scanner.pos
else
scanner.charpos
end
end
def empty_params_result
[
[],
[],
nil,
[],
{},
{},
nil
]
end
KEYWORDS = {
"class" => :kCLASS,
"type" => :kTYPE,
"def" => :kDEF,
"self" => :kSELF,
"void" => :kVOID,
"any" => :kANY,
"untyped" => :kUNTYPED,
"top" => :kTOP,
"bot" => :kBOT,
"instance" => :kINSTANCE,
"bool" => :kBOOL,
"nil" => :kNIL,
"true" => :kTRUE,
"false" => :kFALSE,
"singleton" => :kSINGLETON,
"interface" => :kINTERFACE,
"end" => :kEND,
"include" => :kINCLUDE,
"extend" => :kEXTEND,
"prepend" => :kPREPEND,
"module" => :kMODULE,
"attr_reader" => :kATTRREADER,
"attr_writer" => :kATTRWRITER,
"attr_accessor" => :kATTRACCESSOR,
"public" => :kPUBLIC,
"private" => :kPRIVATE,
"alias" => :kALIAS,
"extension" => :kEXTENSION,
"incompatible" => :kINCOMPATIBLE,
"unchecked" => :kUNCHECKED,
"overload" => :kOVERLOAD,
"out" => :kOUT,
"in" => :kIN,
}
KEYWORDS_RE = /#{Regexp.union(*KEYWORDS.keys)}\b/
PUNCTS = {
"===" => :tOPERATOR,
"==" => :tOPERATOR,
"=~" => :tOPERATOR,
"!~" => :tOPERATOR,
"!=" => :tOPERATOR,
">=" => :tOPERATOR,
"<<" => :tOPERATOR,
"<=>" => :tOPERATOR,
"<=" => :tOPERATOR,
">>" => :tOPERATOR,
">" => :tOPERATOR,
"~" => :tOPERATOR,
"+@" => :tOPERATOR,
"+" => :tOPERATOR,
"[]=" => :tOPERATOR,
"[]" => :tOPERATOR,
"::" => :kCOLON2,
":" => :kCOLON,
"(" => :kLPAREN,
")" => :kRPAREN,
"[" => :kLBRACKET,
"]" => :kRBRACKET,
"{" => :kLBRACE,
"}" => :kRBRACE,
"," => :kCOMMA,
"|" => :kBAR,
"&" => :kAMP,
"^" => :kHAT,
"->" => :kARROW,
"=>" => :kFATARROW,
"=" => :kEQ,
"?" => :kQUESTION,
"!" => :kEXCLAMATION,
"**" => :kSTAR2,
"*" => :kSTAR,
"..." => :kDOT3,
"." => :kDOT,
"<" => :kLT,
"-@" => :tOPERATOR,
"-" => :tOPERATOR,
"/" => :tOPERATOR,
"`" => :tOPERATOR,
"%" => :tOPERATOR,
}
PUNCTS_RE = Regexp.union(*PUNCTS.keys)
ANNOTATION_RE = Regexp.union(/%a\{.*?\}/,
/%a\[.*?\]/,
/%a\(.*?\)/,
/%a\<.*?\>/,
/%a\|.*?\|/)
escape_sequences = %w[a b e f n r s t v "].map { |l| "\\\\#{l}" }
DBL_QUOTE_STR_ESCAPE_SEQUENCES_RE = /(#{escape_sequences.join("|")})/
def next_token
if @type
type = @type
@type = nil
return [:"type_#{type}", nil]
end
return new_token(false, '') if @eof
while true
return new_token(false, '') if input.eos?
case
when input.scan(/\s+/)
# skip
when input.scan(/#(( *)|( ?(?<string>.*)))\n/)
charpos = charpos(input)
start_index = charpos - input.matched.size
end_index = charpos-1
location = RBS::Location.new(buffer: buffer,
start_pos: start_index,
end_pos: end_index)
push_comment input[:string] || "", location
else
break
end
end
case
when eof_re && input.scan(eof_re)
@eof = true
[:tEOF, input.matched]
when input.scan(/`[a-zA-Z_]\w*`/)
s = input.matched.yield_self {|s| s[1, s.length-2] }
new_token(:tQUOTEDIDENT, s)
when input.scan(/`(\\`|[^` :])+`/)
s = input.matched.yield_self {|s| s[1, s.length-2] }.gsub(/\\`/, '`')
new_token(:tQUOTEDMETHOD, s)
when input.scan(ANNOTATION_RE)
s = input.matched.yield_self {|s| s[3, s.length-4] }.strip
new_token(:tANNOTATION, s)
when input.scan(/self\?/)
new_token(:kSELFQ, "self?")
when input.scan(/(([a-zA-Z]\w*)|(_\w+))=/)
new_token(:tWRITE_ATTR)
when input.scan(KEYWORDS_RE)
new_token(KEYWORDS[input.matched], input.matched.to_sym)
when input.scan(/:((@{,2}|\$)?\w+(\?|\!)?|[|&\/%~`^]|<=>|={2,3}|=~|[<>]{2}|[<>]=?|[-+]@?|\*{1,2}|\[\]=?|![=~]?)\b?/)
s = input.matched.yield_self {|s| s[1, s.length] }.to_sym
new_token(:tSYMBOL, s)
when input.scan(/[+-]?\d[\d_]*/)
new_token(:tINTEGER, input.matched.to_i)
when input.scan(PUNCTS_RE)
new_token(PUNCTS[input.matched])
when input.scan(/(::)?([A-Z]\w*::)+/)
new_token(:tNAMESPACE)
when input.scan(/[a-z_]\w*:/)
new_token(:tLKEYWORD, input.matched.chop.to_sym)
when input.scan(/[a-z_]\w*[?!]:/)
new_token(:tLKEYWORD_Q_E, input.matched.chop.to_sym)
when input.scan(/[A-Z]\w*:/)
new_token(:tUKEYWORD, input.matched.chop.to_sym)
when input.scan(/[A-Z]\w*[?!]:/)
new_token(:tUKEYWORD_Q_E, input.matched.chop.to_sym)
when input.scan(/\$[A-Za-z_]\w*/)
new_token(:tGLOBALIDENT)
when input.scan(/@[a-zA-Z_]\w*/)
new_token(:tIVAR, input.matched.to_sym)
when input.scan(/@@[a-zA-Z_]\w*/)
new_token(:tCLASSVAR, input.matched.to_sym)
when input.scan(/_[a-zA-Z]\w*\b/)
new_token(:tINTERFACEIDENT)
when input.scan(/[A-Z]\w*\b/)
new_token(:tUIDENT)
when input.scan(/[a-z_]\w*\b/)
new_token(:tLIDENT)
when input.scan(/"(\\"|[^"])*"/)
s = input.matched.yield_self {|s| s[1, s.length - 2] }
.gsub(DBL_QUOTE_STR_ESCAPE_SEQUENCES_RE) do |match|
case match
when '\\a' then "\a"
when '\\b' then "\b"
when '\\e' then "\e"
when '\\f' then "\f"
when '\\n' then "\n"
when '\\r' then "\r"
when '\\s' then "\s"
when '\\t' then "\t"
when '\\v' then "\v"
when '\\"' then '"'
end
end
new_token(:tSTRING, s)
when input.scan(/'(\\'|[^'])*'/)
s = input.matched.yield_self {|s| s[1, s.length - 2] }.gsub(/\\'/, "'")
new_token(:tSTRING, s)
else
raise "Unexpected token: #{input.peek(10)}..."
end
end
def on_error(token_id, error_value, value_stack)
raise SyntaxError.new(token_str: token_to_str(token_id), error_value: error_value, value_stack: value_stack)
end
class SyntaxError < StandardError
attr_reader :token_str, :error_value, :value_stack
def initialize(token_str:, error_value:, value_stack: nil)
@token_str = token_str
@error_value = error_value
@value_stack = value_stack
super "parse error on value: #{error_value.inspect} (#{token_str})"
end
end
class SemanticsError < StandardError
attr_reader :subject, :location, :original_message
def initialize(message, subject:, location:)
@subject = subject
@location = location
@original_message = message
super "parse error on #{location}: #{message}"
end
end
---- footer
File Manager Version 1.0, Coded By Lucas
Email: hehe@yahoo.com