Module: Kapusta::Compiler::Language

Defined in:
lib/kapusta/compiler/language.rb

Defined Under Namespace

Classes: AccumulateForm, BindingForm, CaseForm, CatchClause, ClassForm, ConditionalBodyForm, CountedForForm, DotTarget, FaccumulateForm, FinallyClause, FunctionForm, GlobalForm, HashFnForm, ImportMacrosForm, IterationForm, LetForm, LuaIteratorForm, LuaPcallForm, LuaXpcallForm, MacroDefinitionForm, ModuleForm, OrPattern, PinPattern, SetForm, SigilForm, TryForm, TsetForm, UnpackCall, ValuesForm, WherePattern

Constant Summary collapse

FUNCTION_HEADS =
%w[fn lambda λ].freeze
FUNCTION_DEFINITION_HEADS =
(FUNCTION_HEADS + %w[defn]).freeze
MACRO_FUNCTION_HEADS =
(FUNCTION_HEADS + %w[macro]).freeze
BINDING_HEADS =
%w[local var].freeze
HEADER_HEADS =
%w[class module].freeze
HEADER_SCOPES =
%i[module class].freeze
DEFINITION_SCOPES =
([:toplevel] + HEADER_SCOPES).freeze
THREAD_HEADS =
%w[-> ->> -?> -?>>].freeze
PIPELINE_HEADS =
(THREAD_HEADS + %w[doto]).freeze
SHORT_PIPELINE_HEADS =
%w[-?> -?>>].freeze
THREAD_FIRST_HEADS =
%w[-> -?>].freeze
SEQUENCE_STATEMENT_HEADS =
%w[let while for each case match].freeze
MULTILINE_BODY_HEADS =
%w[
  if case match let try catch finally do for -> ->> -?> -?>> doto
  fn lambda λ macro
].freeze
FLAT_BODY_HEADS =
%w[
  fn lambda λ macro when unless for each icollect collect fcollect
  accumulate faccumulate
].freeze
NEVER_FLAT_HEADS =
%w[let case match try catch finally do -> ->> -?> -?>> doto].freeze
QUASI_HEADS =
%w[
  quasi-sym quasi-list quasi-list-tail quasi-vec quasi-vec-tail
  quasi-hash quasi-gensym
].freeze
CORE_SPECIAL_FORMS =
%w[
  fn defn lambda λ let local var global set if when unless case match
  while for each do values
  -> ->> -?> -?>> doto
  icollect collect fcollect accumulate faccumulate
  hashfn
  . ?: :
  ..
  length
  require
  module class end
  try catch finally
  raise
  ivar cvar gvar
  ruby
  tset
  and or not
  = not= < <= > >=
  + - * / %
  print
  macro macros import-macros
  quasi-sym quasi-list quasi-list-tail quasi-vec quasi-vec-tail quasi-hash quasi-gensym
].freeze
SPECIAL_FORMS =
(CORE_SPECIAL_FORMS + LuaCompat::SPECIAL_FORMS).freeze

Class Method Summary collapse

Class Method Details

.binding_form?(form) ⇒ Boolean

Returns:

  • (Boolean)


203
204
205
206
# File 'lib/kapusta/compiler/language.rb', line 203

def binding_form?(form)
  name = list_head_name(form)
  !name.nil? && binding_head?(name)
end

.binding_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


216
# File 'lib/kapusta/compiler/language.rb', line 216

def binding_head?(name) = BINDING_HEADS.include?(name)

.bodyless_header?(form) ⇒ Boolean

Returns:

  • (Boolean)


240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/kapusta/compiler/language.rb', line 240

def bodyless_header?(form)
  return false unless header_form?(form)

  case form.head.name
  when 'module'
    parsed = parse_module_form(form)
    parsed.body.empty? || (parsed.body.length == 1 && bodyless_header?(parsed.body[0]))
  when 'class'
    parse_class_form(form).body.empty?
  else
    false
  end
end

.definition_scope?(scope) ⇒ Boolean

Returns:

  • (Boolean)


222
# File 'lib/kapusta/compiler/language.rb', line 222

def definition_scope?(scope) = DEFINITION_SCOPES.include?(scope)

.defn_form?(form) ⇒ Boolean

Returns:

  • (Boolean)


191
# File 'lib/kapusta/compiler/language.rb', line 191

def defn_form?(form) = list_head?(form, 'defn')

.do_form?(form) ⇒ Boolean

Returns:

  • (Boolean)


189
# File 'lib/kapusta/compiler/language.rb', line 189

def do_form?(form) = list_head?(form, 'do')

.end_form?(form) ⇒ Boolean

Returns:

  • (Boolean)


187
# File 'lib/kapusta/compiler/language.rb', line 187

def end_form?(form) = list_head?(form, 'end')

.exception_class_form?(form) ⇒ Boolean

Returns:

  • (Boolean)


317
318
319
# File 'lib/kapusta/compiler/language.rb', line 317

def exception_class_form?(form)
  form.is_a?(Sym) && (form.name.match?(/\A[A-Z]/) || form.dotted?)
end

.flat_body_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


234
# File 'lib/kapusta/compiler/language.rb', line 234

def flat_body_head?(name) = FLAT_BODY_HEADS.include?(name)

.function_definition_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


212
# File 'lib/kapusta/compiler/language.rb', line 212

def function_definition_head?(name) = FUNCTION_DEFINITION_HEADS.include?(name)

.function_form?(form, heads: FUNCTION_HEADS) ⇒ Boolean

Returns:

  • (Boolean)


254
255
256
# File 'lib/kapusta/compiler/language.rb', line 254

def function_form?(form, heads: FUNCTION_HEADS)
  !parse_function_form(form, heads:).nil?
end

.function_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


210
# File 'lib/kapusta/compiler/language.rb', line 210

def function_head?(name) = FUNCTION_HEADS.include?(name)

.header_form?(form) ⇒ Boolean

Returns:

  • (Boolean)


193
194
195
196
# File 'lib/kapusta/compiler/language.rb', line 193

def header_form?(form)
  name = list_head_name(form)
  !name.nil? && header_head?(name)
end

.header_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


218
# File 'lib/kapusta/compiler/language.rb', line 218

def header_head?(name) = HEADER_HEADS.include?(name)

.header_scope?(scope) ⇒ Boolean

Returns:

  • (Boolean)


220
# File 'lib/kapusta/compiler/language.rb', line 220

def header_scope?(scope) = HEADER_SCOPES.include?(scope)

.list_head(form) ⇒ Object



171
172
173
174
175
# File 'lib/kapusta/compiler/language.rb', line 171

def list_head(form)
  return unless form.is_a?(List) && !form.empty?

  form.head
end

.list_head?(form, *names) ⇒ Boolean

Returns:

  • (Boolean)


182
183
184
185
# File 'lib/kapusta/compiler/language.rb', line 182

def list_head?(form, *names)
  name = list_head_name(form)
  !name.nil? && names.flatten.include?(name)
end

.list_head_name(form) ⇒ Object



177
178
179
180
# File 'lib/kapusta/compiler/language.rb', line 177

def list_head_name(form)
  head = list_head(form)
  head.name if head.is_a?(Sym)
end

.macro_function_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


214
# File 'lib/kapusta/compiler/language.rb', line 214

def macro_function_head?(name) = MACRO_FUNCTION_HEADS.include?(name)

.multiline_body_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


232
# File 'lib/kapusta/compiler/language.rb', line 232

def multiline_body_head?(name) = MULTILINE_BODY_HEADS.include?(name)

.never_flat_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


236
# File 'lib/kapusta/compiler/language.rb', line 236

def never_flat_head?(name) = NEVER_FLAT_HEADS.include?(name)

.parse_accumulate_args(args) ⇒ Object



491
492
493
# File 'lib/kapusta/compiler/language.rb', line 491

def parse_accumulate_args(args)
  AccumulateForm.new(bindings: args[0], body: args[1..] || [])
end

.parse_accumulate_form(form) ⇒ Object



495
496
497
498
499
# File 'lib/kapusta/compiler/language.rb', line 495

def parse_accumulate_form(form)
  return unless list_head?(form, 'accumulate')

  parse_accumulate_args(form.rest)
end

.parse_binding_args(head, args) ⇒ Object



327
328
329
330
331
# File 'lib/kapusta/compiler/language.rb', line 327

def parse_binding_args(head, args)
  return unless args.length == 2

  BindingForm.new(head:, target: args[0], value: args[1])
end

.parse_binding_form(form) ⇒ Object



321
322
323
324
325
# File 'lib/kapusta/compiler/language.rb', line 321

def parse_binding_form(form)
  return unless binding_form?(form)

  parse_binding_args(form.head.name, form.rest)
end

.parse_case_args(args) ⇒ Object



441
442
443
# File 'lib/kapusta/compiler/language.rb', line 441

def parse_case_args(args)
  CaseForm.new(subject: args[0], clauses: args[1..] || [])
end

.parse_case_form(form) ⇒ Object



445
446
447
448
449
# File 'lib/kapusta/compiler/language.rb', line 445

def parse_case_form(form)
  return unless list_head?(form, %w[case match])

  parse_case_args(form.rest)
end

.parse_catch_clause(args) ⇒ Object



309
310
311
312
313
314
315
# File 'lib/kapusta/compiler/language.rb', line 309

def parse_catch_clause(args)
  if exception_class_form?(args[0])
    CatchClause.new(klass: args[0], bind_sym: args[1], body: args[2..] || [])
  else
    CatchClause.new(klass: nil, bind_sym: args[0], body: args[1..] || [])
  end
end

.parse_class_args(args) ⇒ Object



288
289
290
291
292
293
294
# File 'lib/kapusta/compiler/language.rb', line 288

def parse_class_args(args)
  if args[1].is_a?(Vec)
    ClassForm.new(name: args[0], supers: args[1], body: args[2..] || [], prefix_length: 2)
  else
    ClassForm.new(name: args[0], supers: nil, body: args[1..] || [], prefix_length: 1)
  end
end

.parse_class_form(form) ⇒ Object



272
273
274
275
276
# File 'lib/kapusta/compiler/language.rb', line 272

def parse_class_form(form)
  return unless list_head?(form, 'class')

  parse_class_args(form.rest)
end

.parse_conditional_body_args(args) ⇒ Object



367
368
369
# File 'lib/kapusta/compiler/language.rb', line 367

def parse_conditional_body_args(args)
  ConditionalBodyForm.new(condition: args[0], body: args[1..] || [])
end

.parse_counted_for_args(args) ⇒ Object



511
512
513
# File 'lib/kapusta/compiler/language.rb', line 511

def parse_counted_for_args(args)
  CountedForForm.new(bindings: args[0], body: args[1..] || [])
end

.parse_counted_for_form(form) ⇒ Object



515
516
517
518
519
# File 'lib/kapusta/compiler/language.rb', line 515

def parse_counted_for_form(form)
  return unless list_head?(form, %w[for fcollect])

  parse_counted_for_args(form.rest)
end

.parse_dot_target(form) ⇒ Object



355
356
357
358
359
# File 'lib/kapusta/compiler/language.rb', line 355

def parse_dot_target(form)
  return unless list_head?(form, ':')

  DotTarget.new(object: form.items[1], keys: form.items[2..] || [])
end

.parse_faccumulate_args(args) ⇒ Object



501
502
503
# File 'lib/kapusta/compiler/language.rb', line 501

def parse_faccumulate_args(args)
  FaccumulateForm.new(bindings: args[0], body: args[1..] || [])
end

.parse_faccumulate_form(form) ⇒ Object



505
506
507
508
509
# File 'lib/kapusta/compiler/language.rb', line 505

def parse_faccumulate_form(form)
  return unless list_head?(form, 'faccumulate')

  parse_faccumulate_args(form.rest)
end

.parse_function_args(args, head: nil) ⇒ Object



264
265
266
267
268
269
270
# File 'lib/kapusta/compiler/language.rb', line 264

def parse_function_args(args, head: nil)
  if args[0].is_a?(Vec)
    FunctionForm.new(head:, name: nil, params: args[0], body: args[1..] || [], prefix_length: 1)
  elsif args[0].is_a?(Sym) && args[1].is_a?(Vec)
    FunctionForm.new(head:, name: args[0], params: args[1], body: args[2..] || [], prefix_length: 2)
  end
end

.parse_function_form(form, heads: FUNCTION_HEADS) ⇒ Object



258
259
260
261
262
# File 'lib/kapusta/compiler/language.rb', line 258

def parse_function_form(form, heads: FUNCTION_HEADS)
  return unless list_head?(form, heads)

  parse_function_args(form.rest, head: form.head)
end

.parse_global_args(args) ⇒ Object



333
334
335
336
337
# File 'lib/kapusta/compiler/language.rb', line 333

def parse_global_args(args)
  return unless args.length == 2

  GlobalForm.new(name: args[0], value: args[1])
end

.parse_global_form(form) ⇒ Object



339
340
341
342
343
# File 'lib/kapusta/compiler/language.rb', line 339

def parse_global_form(form)
  return unless list_head?(form, 'global')

  parse_global_args(form.rest)
end

.parse_hashfn_form(form) ⇒ Object



405
406
407
408
409
# File 'lib/kapusta/compiler/language.rb', line 405

def parse_hashfn_form(form)
  return unless list_head?(form, 'hashfn')

  HashFnForm.new(body: form.rest)
end

.parse_import_macros_args(args) ⇒ Object



421
422
423
# File 'lib/kapusta/compiler/language.rb', line 421

def parse_import_macros_args(args)
  ImportMacrosForm.new(destructure: args[0], module_arg: args[1])
end

.parse_import_macros_form(form) ⇒ Object



425
426
427
428
429
# File 'lib/kapusta/compiler/language.rb', line 425

def parse_import_macros_form(form)
  return unless list_head?(form, 'import-macros')

  parse_import_macros_args(form.rest)
end

.parse_iteration_args(args) ⇒ Object



481
482
483
# File 'lib/kapusta/compiler/language.rb', line 481

def parse_iteration_args(args)
  IterationForm.new(bindings: args[0], body: args[1..] || [])
end

.parse_iteration_form(form) ⇒ Object



485
486
487
488
489
# File 'lib/kapusta/compiler/language.rb', line 485

def parse_iteration_form(form)
  return unless list_head?(form, %w[each collect icollect])

  parse_iteration_args(form.rest)
end

.parse_let_args(args) ⇒ Object



431
432
433
# File 'lib/kapusta/compiler/language.rb', line 431

def parse_let_args(args)
  LetForm.new(bindings: args[0], body: args[1..] || [])
end

.parse_let_form(form) ⇒ Object



435
436
437
438
439
# File 'lib/kapusta/compiler/language.rb', line 435

def parse_let_form(form)
  return unless list_head?(form, 'let')

  parse_let_args(form.rest)
end

.parse_lua_iterator_form(form) ⇒ Object



377
378
379
380
381
382
# File 'lib/kapusta/compiler/language.rb', line 377

def parse_lua_iterator_form(form)
  head = list_head(form)
  return unless head.is_a?(Sym) && LuaCompat.iterator_form?(head.name)

  LuaIteratorForm.new(head:, collection: form.items[1])
end

.parse_lua_pcall_args(args) ⇒ Object



384
385
386
# File 'lib/kapusta/compiler/language.rb', line 384

def parse_lua_pcall_args(args)
  LuaPcallForm.new(callable: args[0], args: args[1..] || [])
end

.parse_lua_xpcall_args(args) ⇒ Object



388
389
390
# File 'lib/kapusta/compiler/language.rb', line 388

def parse_lua_xpcall_args(args)
  LuaXpcallForm.new(callable: args[0], handler: args[1], args: args[2..] || [])
end

.parse_macro_definition_args(args) ⇒ Object



411
412
413
# File 'lib/kapusta/compiler/language.rb', line 411

def parse_macro_definition_args(args)
  MacroDefinitionForm.new(name: args[0], params: args[1], body: args[2..] || [])
end

.parse_macro_definition_form(form) ⇒ Object



415
416
417
418
419
# File 'lib/kapusta/compiler/language.rb', line 415

def parse_macro_definition_form(form)
  return unless list_head?(form, 'macro')

  parse_macro_definition_args(form.rest)
end

.parse_module_args(args) ⇒ Object



284
285
286
# File 'lib/kapusta/compiler/language.rb', line 284

def parse_module_args(args)
  ModuleForm.new(name: args[0], body: args[1..] || [], prefix_length: 1)
end

.parse_module_form(form) ⇒ Object



278
279
280
281
282
# File 'lib/kapusta/compiler/language.rb', line 278

def parse_module_form(form)
  return unless list_head?(form, 'module')

  parse_module_args(form.rest)
end

.parse_or_pattern(pattern) ⇒ Object



463
464
465
466
467
# File 'lib/kapusta/compiler/language.rb', line 463

def parse_or_pattern(pattern)
  return unless list_head?(pattern, 'or')

  OrPattern.new(alternatives: pattern.items[1..] || [])
end

.parse_pin_pattern(pattern) ⇒ Object



469
470
471
472
473
# File 'lib/kapusta/compiler/language.rb', line 469

def parse_pin_pattern(pattern)
  return unless list_head?(pattern, '=') && pattern.items.length == 2

  PinPattern.new(name: pattern.items[1])
end

.parse_set_args(args) ⇒ Object



351
352
353
# File 'lib/kapusta/compiler/language.rb', line 351

def parse_set_args(args)
  SetForm.new(target: args[0], value: args[1])
end

.parse_set_form(form) ⇒ Object



345
346
347
348
349
# File 'lib/kapusta/compiler/language.rb', line 345

def parse_set_form(form)
  return unless list_head?(form, 'set')

  parse_set_args(form.rest)
end

.parse_sigil_args(head, args) ⇒ Object



399
400
401
402
403
# File 'lib/kapusta/compiler/language.rb', line 399

def parse_sigil_args(head, args)
  return unless %w[ivar cvar gvar].include?(head)

  SigilForm.new(head:, name: args[0])
end

.parse_sigil_form(form) ⇒ Object



392
393
394
395
396
397
# File 'lib/kapusta/compiler/language.rb', line 392

def parse_sigil_form(form)
  head = list_head_name(form)
  return unless head

  parse_sigil_args(head, form.rest)
end

.parse_try_args(args) ⇒ Object



296
297
298
# File 'lib/kapusta/compiler/language.rb', line 296

def parse_try_args(args)
  TryForm.new(body: args[0], clauses: (args[1..] || []).filter_map { |clause| parse_try_clause(clause) })
end

.parse_try_clause(clause) ⇒ Object



300
301
302
303
304
305
306
307
# File 'lib/kapusta/compiler/language.rb', line 300

def parse_try_clause(clause)
  return unless list_head_name(clause)

  case clause.head.name
  when 'catch' then parse_catch_clause(clause.rest)
  when 'finally' then FinallyClause.new(body: clause.rest)
  end
end

.parse_try_form(form) ⇒ Object



451
452
453
454
455
# File 'lib/kapusta/compiler/language.rb', line 451

def parse_try_form(form)
  return unless list_head?(form, 'try')

  parse_try_args(form.rest)
end

.parse_tset_args(args) ⇒ Object



361
362
363
364
365
# File 'lib/kapusta/compiler/language.rb', line 361

def parse_tset_args(args)
  return unless args.length >= 3

  TsetForm.new(table: args[0], key: args[1], value: args[2])
end

.parse_unpack_call(form) ⇒ Object



475
476
477
478
479
# File 'lib/kapusta/compiler/language.rb', line 475

def parse_unpack_call(form)
  return unless list_head?(form, 'unpack')

  UnpackCall.new(value: form.items[1])
end

.parse_values_form(form) ⇒ Object



371
372
373
374
375
# File 'lib/kapusta/compiler/language.rb', line 371

def parse_values_form(form)
  return unless list_head?(form, 'values') && form.items.length == 3

  ValuesForm.new(key: form.items[1], value: form.items[2])
end

.parse_where_pattern(pattern) ⇒ Object



457
458
459
460
461
# File 'lib/kapusta/compiler/language.rb', line 457

def parse_where_pattern(pattern)
  return unless list_head?(pattern, 'where')

  WherePattern.new(inner: pattern.items[1], guards: pattern.items[2..] || [])
end

.pipeline_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


224
# File 'lib/kapusta/compiler/language.rb', line 224

def pipeline_head?(name) = PIPELINE_HEADS.include?(name)

.quasi_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


238
# File 'lib/kapusta/compiler/language.rb', line 238

def quasi_head?(name) = QUASI_HEADS.include?(name)

.sequence_statement_form?(form) ⇒ Boolean

Returns:

  • (Boolean)


198
199
200
201
# File 'lib/kapusta/compiler/language.rb', line 198

def sequence_statement_form?(form)
  name = list_head_name(form)
  !name.nil? && sequence_statement_head?(name)
end

.sequence_statement_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


230
# File 'lib/kapusta/compiler/language.rb', line 230

def sequence_statement_head?(name) = SEQUENCE_STATEMENT_HEADS.include?(name)

.short_pipeline_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


226
# File 'lib/kapusta/compiler/language.rb', line 226

def short_pipeline_head?(name) = SHORT_PIPELINE_HEADS.include?(name)

.special_form?(name) ⇒ Boolean

Returns:

  • (Boolean)


208
# File 'lib/kapusta/compiler/language.rb', line 208

def special_form?(name) = SPECIAL_FORMS.include?(name)

.thread_first_head?(name) ⇒ Boolean

Returns:

  • (Boolean)


228
# File 'lib/kapusta/compiler/language.rb', line 228

def thread_first_head?(name) = THREAD_FIRST_HEADS.include?(name)