Skip to content
Merged
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
8 changes: 8 additions & 0 deletions lib/rouge/demos/dylan
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Various keywords and constants
define method demo(x :: <integer>, #key y = "demo") => ()
let z = #xFEE8 + #o277;
let w = '\n';
format-out("%d %s %d %c", x + 100, y, z, w);
end method;

demo(99, y: "hello");
107 changes: 107 additions & 0 deletions lib/rouge/lexers/dylan.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
module Lexers
class Dylan < RegexLexer
title 'Dylan'
desc 'Dylan Language (https://opendylan.org)'
tag 'dylan'
filenames '*.dylan'

# Definitions from the Dylan Reference Manual
# see:
# https://opendylan.org/books/drm/Modules
# https://opendylan.org/books/drm/Conditional_Execution
# https://opendylan.org/books/drm/Statement_Macros
reserved_words = Set.new %w(
begin block case class constant create define domain else
end exception for function generic handler if let library local
macro method module otherwise select unless until variable while
)

hash_word = Set.new %w(#t #f #next #rest #key #all-keys #include)
operators = Set.new %w(+ - * / ^ = == ~ ~= ~== < <= > >= & | :=)

state :root do
rule %r/^[\w.-]+:/, Comment::Preproc, :header
rule %r/\s+/, Text::Whitespace
rule(%r//) { goto :main }
end

# see https://opendylan.org/books/drm/Dylan_Interchange_Format
state :header do
rule(/.*?$/) { token Comment; goto :header_value }
end

state :header_value do
# line continuations are defined as any line that starts with whitespace
rule %r/^[ \t]+.*?$/, Comment
rule %r/\n+/, Comment
rule(//) { pop! }
end

state :main do
# Comments
rule %r(//.*?$), Comment::Single
rule %r(/\*.*?\*/)m, Comment::Multiline
rule %r/\s+/, Text::Whitespace

# Keywords
rule %r/\w+/ do |m|
if reserved_words.include?(m[0])
token Keyword
elsif hash_word.include?(m[0])
token Keyword::Constant
else
fallthrough!
end
end

rule %r/#(t|f|next|rest|key|all-keys|include)\b/, Keyword::Constant

# Numbers
rule %r([+-]?\d+/\d+), Literal::Number::Other
rule %r/[+-]?\d*[.]\d+(?:e[+-]?\d+)?/i, Literal::Number::Float
rule %r/[+-]?\d+[.]\d*(?:e[+-]?\d+)?/i, Literal::Number::Float
rule %r/[+-]\d+(?:e[+-]?\d+)?/i, Literal::Number::Float
rule %r/#b[01]+/, Literal::Number::Bin
rule %r/#o[0-7]+/, Literal::Number::Oct
rule %r/[+-]?[0-9]+/, Literal::Number::Integer
rule %r/#x[0-9a-f]+/i, Literal::Number::Hex

# Names
rule %r/[+-]/, Operator

# Operators and punctuation
rule %r/::|=>|#[(\[#]|[.][.][.]|[(),.;\[\]{}=?]/, Punctuation

rule %r([\w!&*<>|^\$%@][\w!&*<>|^\$%@=/?~+-]*) do |m|
word = m[0]
if operators.include?(m[0])
token Operator
elsif word.start_with?('<') && word.end_with?('>')
token Name::Class
elsif word.start_with?('*') && word.end_with?('*')
token Name::Variable::Instance
elsif word.start_with?('$')
token Name::Constant
else
token Name
end
end

rule %r/:/, Operator # For 'constrained names'
# Strings, characters and whitespace
rule %r/"/, Str::Double, :dq
rule %r/'([^\\']|(\\[\\'abefnrt0])|(\\[0-9a-f]+))'/, Str::Char
end

state :dq do
rule %r/\\[\\'"abefnrt0]/, Str::Escape
rule %r/[^\\"]+/, Str::Double
rule %r/"/, Str::Double, :pop!
end
end
end
end
14 changes: 14 additions & 0 deletions spec/lexers/dylan_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

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

describe 'guessing' do
include Support::Guessing

it 'guesses by filename' do
assert_guess :filename => 'myfile.dylan'
end
end
end
51 changes: 51 additions & 0 deletions spec/visual/samples/dylan
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
Module: Factorial
Synopsis: Factorial "application."
Author: Steve Rowley
Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc.
All rights reserved.
License: See License.txt in this distribution for details.
Warranty: Distributed WITHOUT WARRANTY OF ANY KIND

///
/// The canonical recursive function.
///

define function factorial (n :: <integer>) => (n! :: <integer>)
case
n < 0 => error("Can't take factorial of negative integer: %d\n", n);
n = 0 => 1;
otherwise => n * factorial(n - 1);
end
end;

define function factorial-top-level () => ()
let arguments = application-arguments();
if (arguments.size == 0)
format-out("Usage: %s number ...\n", application-name());
else
format-out("$maximum-integer = %d\n", $maximum-integer);
format-out("$minimum-integer = %d\n", $minimum-integer);
for (i from 0 below size(arguments))
let arg = arguments[i];
block (loop-continue)
let n = block ()
string-to-integer(arg);
exception (<error>)
format-out("Skipping invalid argument %=.\n", arg);
loop-continue();
end block;
let n! = 0;
profiling (cpu-time-seconds, cpu-time-microseconds)
n! := factorial(n)
results
format-out("factorial(%d) = %d (in %d.%s seconds)\n", n, n!,
cpu-time-seconds, integer-to-string(cpu-time-microseconds, size: 6));
end profiling;
exception (e :: <error>)
format-out("factorial(%s) - Error: %s\n", arg, e);
end block;
end for;
end if;
end function factorial-top-level;

factorial-top-level();