Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions lib/rouge/demos/lateralus
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// examples/fibonacci.ltl - Fibonacci demonstration

module examples::fibonacci

import std::io

fn fib(n: int) -> int {
if n <= 0 { return 0 }
if n == 1 { return 1 }
return fib(n - 1) + fib(n - 2)
}

fn main() {
io::println("Fibonacci sequence:")
let nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let results = nums |> map(fib)
for (i, r) in results |> enumerate() {
io::println("fib({i}) = {r}")
}
}

main()
152 changes: 152 additions & 0 deletions lib/rouge/lexers/lateralus.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
module Lexers
class Lateralus < RegexLexer
tag 'lateralus'
aliases 'ltl'
filenames '*.ltl'
mimetypes 'text/x-lateralus'

title 'Lateralus'
desc 'The Lateralus programming language (lateralus.dev)'

def self.keywords
@keywords ||= %w(
fn let mut match if else elif while for in return break continue
import export module pub priv struct enum impl trait where type
const static async await spawn guard defer use as self Self super
yield do
)
end

def self.builtin_types
@builtin_types ||= %w(
int i8 i16 i32 i64 i128
uint u8 u16 u32 u64 u128
float f32 f64
bool str char bytes any never
list map set tuple Option Result Some None Ok Err
)
end

def self.builtins
@builtins ||= %w(
print println eprint eprintln format panic assert assert_eq
todo unimplemented unreachable
len range map filter reduce fold zip enumerate
sort sorted reverse sum min max
)
end

def self.constants
@constants ||= %w(true false null)
end

id = /[A-Za-z_][A-Za-z0-9_]*/
type_id = /[A-Z][A-Za-z0-9_]*/
hex = /[0-9a-fA-F]/
int_suf = /(?:_?[iu](?:8|16|32|64|128))?/
flt_suf = /(?:_?f(?:32|64))?/

state :whitespace do
rule %r/\s+/, Text
rule %r(///[^\n]*), Comment::Special
rule %r(//[^\n]*), Comment::Single
rule %r(/\*), Comment::Multiline, :block_comment
end

state :block_comment do
rule %r([^*/]+), Comment::Multiline
rule %r(/\*), Comment::Multiline, :block_comment
rule %r(\*/), Comment::Multiline, :pop!
rule %r([/*]), Comment::Multiline
end

state :strings do
# raw strings: r"...", r#"..."#, r##"..."##, ...
rule %r/r(#*)"(?:\\.|(?!\1").)*"\1/m, Str
# byte strings
rule %r/b"/, Str, :string
# regular / interpolated strings
rule %r/"/, Str, :string
# char literals
rule %r/'(?:\\(?:[nrt'"\\0]|x#{hex}{2}|u\{#{hex}{1,6}\})|[^'\\])'/, Str::Char
end

state :string do
rule %r/"/, Str, :pop!
rule %r/\\(?:[nrt'"\\0]|x#{hex}{2}|u\{#{hex}{1,6}\})/, Str::Escape
rule %r/\{[^}]*\}/, Str::Interpol
rule %r/[^"\\{}]+/, Str
rule %r/[\\{}]/, Str
end

state :attribute do
rule %r/[^\[\]]+/, Name::Decorator
rule %r/\[/, Name::Decorator, :attribute
rule %r/\]/, Name::Decorator, :pop!
end

state :root do
mixin :whitespace
mixin :strings

# Attribute decorators: @memo, @doc("..."), @foreign("c")
rule %r/@#{id}/, Name::Decorator
# Capability annotations: #[caps(io, net)]
rule %r/\#\[/, Name::Decorator, :attribute

# Numeric literals
rule %r/[0-9][0-9_]*\.[0-9][0-9_]*(?:[eE][-+]?[0-9][0-9_]*)?#{flt_suf}/,
Num::Float
rule %r/0x#{hex}[#{hex}_]*#{int_suf}/, Num::Hex
rule %r/0o[0-7][0-7_]*#{int_suf}/, Num::Oct
rule %r/0b[01][01_]*#{int_suf}/, Num::Bin
rule %r/[0-9][0-9_]*#{int_suf}/, Num::Integer

# Pipeline operator (Lateralus's signature feature)
rule %r/\|>/, Operator

# Function / type / struct / enum / trait / impl definitions
rule %r/(fn)(\s+)(#{id})/ do
groups Keyword, Text, Name::Function
end
rule %r/(struct|enum|trait|type|impl)(\s+)(#{type_id})/ do
groups Keyword, Text, Name::Class
end

# Module path segment: `foo::`
rule %r/(#{id})(::)/ do
groups Name::Namespace, Punctuation
end

# Identifiers with semantic lookup
rule id do |m|
name = m[0]
if self.class.keywords.include?(name)
token Keyword
elsif self.class.builtin_types.include?(name)
token Keyword::Type
elsif self.class.constants.include?(name)
token Keyword::Constant
elsif self.class.builtins.include?(name)
token Name::Builtin
elsif name =~ /\A[A-Z]/
token Name::Class
else
token Name
end
end

# Operators
rule %r/==|!=|<=|>=|->|=>|&&|\|\||<<|>>|::|\.\.=?|\?\?|[+\-*\/%<>!=&|^~?]/,
Operator

# Punctuation
rule %r/[{}()\[\];,.:]/, Punctuation
end
end
end
end
66 changes: 66 additions & 0 deletions spec/lexers/lateralus_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

describe Rouge::Lexers::Lateralus do
let(:subject) { Rouge::Lexers::Lateralus.new }

describe 'guessing' do
include Support::Guessing

it 'guesses by filename' do
assert_guess :filename => 'foo.ltl'
end

it 'guesses by mimetype' do
assert_guess :mimetype => 'text/x-lateralus'
end
end

describe 'lexing' do
include Support::Lexing

it 'lexes the pipeline operator' do
assert_tokens_equal 'x |> f',
['Name', 'x'],
['Text', ' '],
['Operator', '|>'],
['Text', ' '],
['Name', 'f']
end

it 'lexes typed integers' do
assert_tokens_equal '42u64', ['Literal.Number.Integer', '42u64']
assert_tokens_equal '0xFF_i32', ['Literal.Number.Hex', '0xFF_i32']
assert_tokens_equal '0b1010u8', ['Literal.Number.Bin', '0b1010u8']
end

it 'lexes typed floats' do
assert_tokens_equal '3.14_f32', ['Literal.Number.Float', '3.14_f32']
end

it 'recognizes keywords and types' do
assert_tokens_equal 'fn', ['Keyword', 'fn']
assert_tokens_equal 'let', ['Keyword', 'let']
assert_tokens_equal 'int', ['Keyword.Type', 'int']
assert_tokens_equal 'str', ['Keyword.Type', 'str']
end

it 'recognizes decorators' do
assert_tokens_equal '@memo', ['Name.Decorator', '@memo']
end

it 'treats UpperCamelCase as a class name' do
assert_tokens_equal 'Some', ['Keyword.Type', 'Some']
assert_tokens_equal 'MyType', ['Name.Class', 'MyType']
end

it 'highlights builtin functions' do
assert_tokens_equal 'println', ['Name.Builtin', 'println']
end

it 'handles line and doc comments' do
assert_tokens_equal '// hi', ['Comment.Single', '// hi']
assert_tokens_equal '/// doc', ['Comment.Special', '/// doc']
end
end
end
22 changes: 22 additions & 0 deletions spec/visual/samples/lateralus
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// examples/fibonacci.ltl - Fibonacci demonstration

module examples::fibonacci

import std::io

fn fib(n: int) -> int {
if n <= 0 { return 0 }
if n == 1 { return 1 }
return fib(n - 1) + fib(n - 2)
}

fn main() {
io::println("Fibonacci sequence:")
let nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let results = nums |> map(fib)
for (i, r) in results |> enumerate() {
io::println("fib({i}) = {r}")
}
}

main()