Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Nim #622

Merged
merged 4 commits into from
Sep 7, 2015
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
4 changes: 4 additions & 0 deletions components.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ var components = {
"title": "NASM",
"owner": "rbmj"
},
"nim": {
"title": "Nim",
"owner": "Golmote"
},
"nsis": {
"title": "NSIS",
"owner": "idleberg"
Expand Down
30 changes: 30 additions & 0 deletions components/prism-nim.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Prism.languages.nim = {
'comment': /#.*/,
// Double-quoted strings can be prefixed by an identifier (Generalized raw string literals)
// Character literals are handled specifically to prevent issues with numeric type suffixes
'string': /(?:(?:\b(?!\d)(?:\w|\\x[8-9a-fA-F][0-9a-fA-F])+)?(?:"""[\s\S]*?"""(?!")|"(?:\\[\s\S]|""|[^"\\])*")|'(?:\\(?:\d+|x[\da-fA-F]{2}|.)|[^'])')/,
// The negative look ahead prevents wrong highlighting of the .. operator
'number': /\b(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:(?!\.\.)\.[\d_]*)?(?:[eE][+-]?\d[\d_]*)?)(?:'?[iuf]\d*)?/,
'keyword': /\b(?:addr|as|asm|atomic|bind|block|break|case|cast|concept|const|continue|converter|defer|discard|distinct|do|elif|else|end|enum|except|export|finally|for|from|func|generic|if|import|include|interface|iterator|let|macro|method|mixin|nil|object|out|proc|ptr|raise|ref|return|static|template|try|tuple|type|using|var|when|while|with|without|yield)\b/,
'function': {
pattern: /(?:(?!\d)(?:\w|\\x[8-9a-fA-F][0-9a-fA-F])+|`[^`\r\n]+`)\*?(?:\[[^\]]+\])?(?=\s*\()/,
inside: {
'operator': /\*$/
}
},
// We don't want to highlight operators inside backticks
'ignore': {
pattern: /`[^`\r\n]+`/,
inside: {
'punctuation': /`/
}
},
'operator': {
// Look behind and look ahead prevent wrong highlighting of punctuations [. .] {. .} (. .)
// but allow the slice operator .. to take precedence over them
// One can define his own operators in Nim so all combination of operators might be an operator.
pattern: /(^|[({\[](?=\.\.)|(?![({\[]\.).)(?:(?:[=+\-*\/<>@$~&%|!?^:\\]|\.\.|\.(?![)}\]]))+|\b(?:and|div|of|or|in|is|isnot|mod|not|notin|shl|shr|xor)\b)/m,
lookbehind: true
},
'punctuation': /[({\[]\.|\.[)}\]]|[`(){}\[\],:]/
};
1 change: 1 addition & 0 deletions components/prism-nim.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

235 changes: 235 additions & 0 deletions examples/prism-nim.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
<h1>Nim</h1>
<p>To use this language, use the class "language-nim".</p>

<h2>Comments</h2>
<pre><code># This is a comment</code></pre>

<h2>Strings</h2>
<pre><code>"This is a string."
"This is a string with \"quotes\" in it."
"""This is
a "multi-line"
string."""
""""A long string within quotes.""""
R"This is a raw string."
r"Some ""quotes"" inside a raw string."
r"""Raw strings
can also be multi-line."""
foo"This is a generalized raw string literal."
bar"""This is also
a generalized raw string literal."""</code></pre>

<h2>Characters</h2>
<pre><code>'a'
'\''
'\t'
'\15'
'\xFC'</code></pre>

<h2>Numbers</h2>
<pre><code>42
0xaf
0xf_2_c
0o07
0b1111_0000
0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64
9_000'u
32.
32.1f32
32.e-5
32.2e+2
2'i16
2i16
0xfe'f32</code></pre>

<h2>Full example</h2>
<pre><code># Example from http://nim-by-example.github.io/oop_macro/
import macros

macro class*(head: expr, body: stmt): stmt {.immediate.} =
# The macro is immediate so that it doesn't
# resolve identifiers passed to it

var typeName, baseName: NimNode

if head.kind == nnkIdent:
# `head` is expression `typeName`
# echo head.treeRepr
# --------------------
# Ident !"Animal"
typeName = head

elif head.kind == nnkInfix and $head[0] == "of":
# `head` is expression `typeName of baseClass`
# echo head.treeRepr
# --------------------
# Infix
# Ident !"of"
# Ident !"Animal"
# Ident !"RootObj"
typeName = head[1]
baseName = head[2]

else:
quit "Invalid node: " & head.lispRepr

# echo treeRepr(body)
# --------------------
# StmtList
# VarSection
# IdentDefs
# Ident !"name"
# Ident !"string"
# Empty
# IdentDefs
# Ident !"age"
# Ident !"int"
# Empty
# MethodDef
# Ident !"vocalize"
# Empty
# Empty
# FormalParams
# Ident !"string"
# Empty
# Empty
# StmtList
# StrLit ...
# MethodDef
# Ident !"age_human_yrs"
# Empty
# Empty
# FormalParams
# Ident !"int"
# Empty
# Empty
# StmtList
# DotExpr
# Ident !"this"
# Ident !"age"

# create a new stmtList for the result
result = newStmtList()

# var declarations will be turned into object fields
var recList = newNimNode(nnkRecList)

# Iterate over the statements, adding `this: T`
# to the parameters of functions
for node in body.children:
case node.kind:

of nnkMethodDef, nnkProcDef:
# inject `this: T` into the arguments
let p = copyNimTree(node.params)
p.insert(1, newIdentDefs(ident"this", typeName))
node.params = p
result.add(node)

of nnkVarSection:
# variables get turned into fields of the type.
for n in node.children:
recList.add(n)

else:
result.add(node)

# The following prints out the AST structure:
#
# import macros
# dumptree:
# type X = ref object of Y
# z: int
# --------------------
# TypeSection
# TypeDef
# Ident !"X"
# Empty
# RefTy
# ObjectTy
# Empty
# OfInherit
# Ident !"Y"
# RecList
# IdentDefs
# Ident !"z"
# Ident !"int"
# Empty

result.insert(0,
if baseName == nil:
quote do:
type `typeName` = ref object of RootObj
else:
quote do:
type `typeName` = ref object of `baseName`
)
# Inspect the tree structure:
#
# echo result.treeRepr
# --------------------
# StmtList
# StmtList
# TypeSection
# TypeDef
# Ident !"Animal"
# Empty
# RefTy
# ObjectTy
# Empty
# OfInherit
# Ident !"RootObj"
# Empty <= We want to replace this
# MethodDef
# ...

result[0][0][0][2][0][2] = recList

# Lets inspect the human-readable version of the output
# echo repr(result)
# Output:
# type
# Animal = ref object of RootObj
# name: string
# age: int
#
# method vocalize(this: Animal): string =
# "..."
#
# method age_human_yrs(this: Animal): int =
# this.age

# ---

class Animal of RootObj:
var name: string
var age: int
method vocalize: string = "..."
method age_human_yrs: int = this.age # `this` is injected

class Dog of Animal:
method vocalize: string = "woof"
method age_human_yrs: int = this.age * 7

class Cat of Animal:
method vocalize: string = "meow"

# ---

var animals: seq[Animal] = @[]
animals.add(Dog(name: "Sparky", age: 10))
animals.add(Cat(name: "Mitten", age: 10))

for a in animals:
echo a.vocalize()
echo a.age_human_yrs()</code></pre>

<h2>Known failures</h2>
<p>There are certain edge cases where Prism will fail.
There are always such cases in every regex-based syntax highlighter.
However, Prism dares to be open and honest about them.
If a failure is listed here, it doesn’t mean it will never be fixed. This is more of a “known bugs” list, just with a certain type of bug.
</p>

<h3>Comment-like substrings</h3>
<pre><code>"This # is a broken string"</code></pre>
13 changes: 13 additions & 0 deletions tests/languages/nim/comment_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#
# Foobar

----------------------------------------------------

[
["comment", "#"],
["comment", "# Foobar"]
]

----------------------------------------------------

Checks for comments.
17 changes: 17 additions & 0 deletions tests/languages/nim/function_feature.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
fo\x9ao(
class*(
takeV[T](
`$`(

----------------------------------------------------

[
["function", ["fo\\x9ao"]], ["punctuation", "("],
["function", ["class", ["operator", "*"]]], ["punctuation", "("],
["function", ["takeV[T]"]], ["punctuation", "("],
["function", ["`$`"]], ["punctuation", "("]
]

----------------------------------------------------

Checks for functions.
Loading