summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pygments/lexers/_mapping.py1
-rw-r--r--pygments/lexers/scripting.py55
-rw-r--r--tests/examplefiles/example.ms286
3 files changed, 340 insertions, 2 deletions
diff --git a/pygments/lexers/_mapping.py b/pygments/lexers/_mapping.py
index af7535e5..40189eff 100644
--- a/pygments/lexers/_mapping.py
+++ b/pygments/lexers/_mapping.py
@@ -275,6 +275,7 @@ LEXERS = {
'MatlabLexer': ('pygments.lexers.matlab', 'Matlab', ('matlab',), ('*.m',), ('text/matlab',)),
'MatlabSessionLexer': ('pygments.lexers.matlab', 'Matlab session', ('matlabsession',), (), ()),
'MiniDLexer': ('pygments.lexers.d', 'MiniD', ('minid',), (), ('text/x-minidsrc',)),
+ 'MiniScriptLexer': ('pygments.lexers.scripting', 'MiniScript', ('ms', 'miniscript'), ('*.ms',), ('text/x-minicript', 'application/x-miniscript')),
'ModelicaLexer': ('pygments.lexers.modeling', 'Modelica', ('modelica',), ('*.mo',), ('text/x-modelica',)),
'Modula2Lexer': ('pygments.lexers.modula2', 'Modula-2', ('modula2', 'm2'), ('*.def', '*.mod'), ('text/x-modula2',)),
'MoinWikiLexer': ('pygments.lexers.markup', 'MoinMoin/Trac Wiki markup', ('trac-wiki', 'moin'), (), ('text/x-trac-wiki',)),
diff --git a/pygments/lexers/scripting.py b/pygments/lexers/scripting.py
index a340f8e0..073c21b7 100644
--- a/pygments/lexers/scripting.py
+++ b/pygments/lexers/scripting.py
@@ -19,7 +19,7 @@ from pygments.util import get_bool_opt, get_list_opt, iteritems
__all__ = ['LuaLexer', 'MoonScriptLexer', 'ChaiscriptLexer', 'LSLLexer',
'AppleScriptLexer', 'RexxLexer', 'MOOCodeLexer', 'HybrisLexer',
- 'EasytrieveLexer', 'JclLexer']
+ 'EasytrieveLexer', 'JclLexer', 'MiniScriptLexer']
class LuaLexer(RegexLexer):
@@ -162,7 +162,6 @@ class LuaLexer(RegexLexer):
continue
yield index, token, value
-
class MoonScriptLexer(LuaLexer):
"""
For `MoonScript <http://moonscript.org>`_ source code.
@@ -1220,3 +1219,55 @@ class JclLexer(RegexLexer):
result = 1.0
assert 0.0 <= result <= 1.0
return result
+
+
+class MiniScriptLexer(RegexLexer):
+ """
+ For `MiniScript <https://miniscript.org>`_ source code.
+ """
+
+ name = "MiniScript"
+ aliases = ["ms", "miniscript"]
+ filenames = ["*.ms"]
+ mimetypes = ['text/x-minicript', 'application/x-miniscript']
+
+ tokens = {
+ 'root': [
+ (r'#!(.*?)$', Comment.Preproc),
+ default('base'),
+ ],
+ 'base': [
+ ('//.*$', Comment.Single),
+ (r'(?i)(\d*\.\d+|\d+\.\d*)(e[+-]?\d+)?', Number),
+ (r'(?i)\d+e[+-]?\d+', Number),
+ (r'\d+', Number),
+ (r'\n', Text),
+ (r'[^\S\n]+', Text),
+ (r'"', String, 'string_double'),
+ (r'(==|!=|<=|>=|[=+\-*/%^<>.:])', Operator),
+ (r'[;,\[\]{}()]', Punctuation),
+ (words((
+ 'break', 'continue', 'else', 'end', 'for', 'function', 'if',
+ 'in', 'isa', 'then', 'repeat', 'return', 'while'), suffix=r'\b'),
+ Keyword),
+ (words((
+ 'abs', 'acos', 'asin', 'atan', 'ceil', 'char', 'cos', 'floor',
+ 'log', 'round', 'rnd', 'pi', 'sign', 'sin', 'sqrt', 'str', 'tan',
+ 'hasIndex', 'indexOf', 'len', 'val', 'code', 'remove', 'lower',
+ 'upper', 'replace', 'split', 'indexes', 'values', 'join', 'sum',
+ 'sort', 'shuffle', 'push', 'pop', 'pull', 'range',
+ 'print', 'input', 'time', 'wait', 'locals', 'globals', 'outer',
+ 'yield'), suffix=r'\b'),
+ Name.Builtin),
+ (r'(true|false|null)\b', Keyword.Constant),
+ (r'(and|or|not|new)\b', Operator.Word),
+ (r'(self|super|__isa)\b', Name.Builtin.Pseudo),
+ (r'[a-zA-Z_]\w*', Name.Variable)
+ ],
+ 'string_double': [
+ (r'[^"\n]+', String),
+ (r'""', String),
+ (r'"', String, '#pop'),
+ (r'\n', Text, '#pop'), # Stray linefeed also terminates strings.
+ ]
+ }
diff --git a/tests/examplefiles/example.ms b/tests/examplefiles/example.ms
new file mode 100644
index 00000000..140a0563
--- /dev/null
+++ b/tests/examplefiles/example.ms
@@ -0,0 +1,286 @@
+// MiniScript (https://miniscript.org) example file,
+// adapted from: http://rosettacode.org/wiki/RCRPG/MiniScript
+
+pos = [0,0,0]
+goal = [floor(rnd*10), floor(rnd*10), floor(3+rnd*5)]
+
+dir = {} // key: direction name; value: [dx, dy, dz]
+dirAbbrevs = {} // key: direction abbrevation; value: full name
+dir.up = [0,0,1]
+dir.down = [0,0,-1]
+dir.north = [0,1,0]
+dir.south = [0,-1,0]
+dir.east = [1,0,0]
+dir.west = [-1,0,0]
+for k in dir.indexes
+ dirAbbrevs[k[0]] = k
+end for
+inverseDir = {"up":"down", "down":"up", "east":"west", "west":"east", "north":"south", "south":"north"}
+
+descNum = function(count, noun)
+ if count == 1 then return "a " + noun
+ return str(count) + " " + noun + "s"
+end function
+
+descList = function(lst)
+ if lst.len == 0 then return ""
+ if lst.len == 1 then return lst[0]
+ if lst.len == 2 then return lst[0] + " and " + lst[1]
+ return lst[:-1].join(", ") + ", and " + lst[-1]
+end function
+
+pickAny = function(options)
+ lst = options.split(";")
+ return lst[rnd * lst.len]
+end function
+
+Contents = {}
+Contents.ladders = 0
+Contents.gold = 0
+Contents.hammers = 0 // (note: a "sledge" is a sled or sleigh, not a sledgehammer)
+Contents.desc = function(prefix, postfix=".")
+ s = []
+ if self.ladders > 0 then s.push descNum(self.ladders, "ladder")
+ if self.hammers > 0 then s.push descNum(self.hammers, "sledgehammer")
+ if self.gold > 0 then s.push descNum(self.gold, "gold coin")
+ if not s then return prefix + " nothing" + postfix
+ return prefix + " " + descList(s) + postfix
+end function
+Contents.initRandom = function()
+ self.ladders = (rnd < 0.3)
+ self.gold = ceil(rnd * 3) * (rnd < 0.1)
+ self.hammers = (rnd < 0.02)
+end function
+Contents.propName = function(obj)
+ if obj == "ladder" or obj == "ladders" then return "ladders"
+ if obj == "gold" or obj == "coin" or obj == "coins" then return "gold"
+ if obj[:6] == "hammer" or obj[:6] == "sledge" then return "hammers"
+ return ""
+end function
+Contents.hasAny = function(obj)
+ pname = Contents.propName(obj)
+ if pname == "" then return false
+ return self[pname] > 0
+end function
+Contents.withdraw = function(obj)
+ result = new Contents
+ if obj == "all" then
+ result.ladders = self.ladders
+ self.ladders = 0
+ result.hammers = self.hammers
+ self.hammers = 0
+ result.gold = self.gold
+ self.gold = 0
+ else
+ pname = Contents.propName(obj)
+ if self[pname] < 1 then return null
+ if obj[-1] == "s" then count = self[pname] else count = 1
+ self[pname] = self[pname] - count
+ result[pname] = count
+ end if
+ return result
+end function
+Contents.deposit = function(c)
+ self.ladders = self.ladders + c.ladders
+ self.hammers = self.hammers + c.hammers
+ self.gold = self.gold + c.gold
+end function
+
+inventory = new Contents
+inventory.hammers = 1
+
+Room = {}
+Room.exits = {}
+Room.color = ""
+Room.init = function(pos)
+ self.contents = new Contents
+ self.contents.initRandom
+ if pos == goal then
+ self.color = "YOU FOUND IT! This is the mystical Room of MacGuffin!"
+ else if rnd < 0.5 then
+ // Give a hint about where the goal is.
+ opt = floor(rnd * 3)
+ if opt == 0 then
+ if goal[2] == pos[2] then
+ hint = "The MacGuffin lies on this level."
+ else if goal[2] > pos[2] then
+ hint = "The MacGuffin rests above."
+ else
+ hint = "The MacGuffin lies below."
+ end if
+ else if opt == 1 then
+ if goal[0] > pos[0] then
+ hint = "The MacGuffin lies to the east."
+ else if goal[0] < pos[0] then
+ hint = "The MacGuffin lies to the west."
+ else
+ hint = "The MacGuffin lies... <undecipherable>"
+ end if
+ else
+ if goal[1] > pos[1] then
+ hint = "The MacGuffin lies to the north."
+ else if goal[1] < pos[1] then
+ hint = "The MacGuffin lies to the south."
+ else
+ hint = "The MacGuffin lies... <undecipherable>"
+ end if
+ end if
+ self.color = "Scratched on the wall is a message: " + hint
+ else if rnd < 0.5 then
+ // Give some random color comment.
+ color = []
+ opt = floor(rnd * 3)
+ if opt == 1 then
+ color.push "You detect " + pickAny("a faint;an odd;a musty;a rotten;an unpleasant")
+ color.push pickAny("smell;odor;scent;stench") + " here."
+ else if opt == 2 then
+ color.push "You can hear a" + pickAny(" faint; quiet; soft; strange;n eerie")
+ color.push pickAny("dripping;scratching;scrabbling;whistling;moaning")
+ color.push pickAny("sound;noise") + " here."
+ else
+ color.push "The " + pickAny("walls here are;floor here is;ceiling of this room is")
+ color.push pickAny("smeared with;discolored by;marred by;covered with")
+ color.push pickAny("dried blood;cobwebs;scratches;gouges;scorch marks;soot;mineral deposits;bits of fur") + "."
+ end if
+ self.color = color.join
+ end if
+ self.exits = {}
+end function
+
+rooms = {} // key: STRING FORM of position; value: Room
+getRoom = function(pos=null)
+ if pos == null then pos = globals.pos
+ key = str(pos)
+ if not rooms.hasIndex(key) then
+ rooms[key] = new Room
+ rooms[key].init pos
+ end if
+ return rooms[key]
+end function
+
+// Commands:
+commands = {}
+help = {}
+
+commands.drop = function(obj)
+ items = inventory.withdraw(obj)
+ if items == null then
+ print "You don't have any " + obj + "."
+ else
+ getRoom.contents.deposit items
+ print items.desc("You drop")
+ end if
+end function
+help.drop = "Drops an item from your inventory into the room. Specify object name or ""all""."
+
+commands.go = function(d)
+ oldRoom = getRoom
+ if dirAbbrevs.hasIndex(d) then d = dirAbbrevs[d]
+ if not dir then
+ print "Which direction?"
+ else if not dir.hasIndex(d) then
+ print "That's not a direction I recognize."
+ else if d == "up" and oldRoom.contents.ladders == 0 then
+ print "There is no ladder in this room to go up."
+ else
+ if not oldRoom.exits.hasIndex(d) then
+ if inventory.hammers < 1 then
+ print "There is no exit that way, and you don't have a sledgehammer."
+ return
+ end if
+ wall = "wall"
+ if d == "up" then wall = "ceiling"
+ if d == "down" then wall = "floor"
+ print "You bash the " + wall + " until you make a passage big enough to crawl through."
+ oldRoom.exits.push d
+ end if
+ delta = dir[d]
+ pos[0] = pos[0] + delta[0]
+ pos[1] = pos[1] + delta[1]
+ pos[2] = pos[2] + delta[2]
+ newRoom = getRoom
+ newRoom.exits.push inverseDir[d]
+ verb = "crawl"
+ if d == "up" then verb = "climb"
+ if d == "down" then
+ if newRoom.contents.ladders > 0 then verb = "climb" else verb = "drop"
+ end if
+ print "You " + verb + " " + d + "."
+ commands.look
+ if pos == goal then
+ print "You have recovered the MacGuffin and " + descNum(inventory.gold, "gold coin") + ". You win!"
+ globals.gameOver = true
+ end if
+ end if
+end function
+help.go = "Moves in the given direction, bashing open a passage if necessary."
+
+commands.help = function(arg)
+ if aliases.hasIndex(arg) then arg = aliases[arg]
+ if help.hasIndex(arg) then
+ print arg + ": " + help[arg]
+ else
+ print "Available commands: " + descList(help.indexes.sort)
+ end if
+end function
+help.help = "Prints the help. Obviously."
+
+commands.inventory = function(arg)
+ print inventory.desc("You have")
+end function
+help.inventory = "Lists the items you are carrying."
+
+commands.look = function(arg)
+ print "You are at " + pos + "."
+ room = getRoom
+ if room.color != "" then print room.color
+ print room.contents.desc("You see", " here.")
+ exits = room.exits.indexes
+ if exits.len == 0 then
+ print "There are no exits."
+ else if room.exits.len == 1 then
+ print "There is a passage " + exits[0] + "."
+ else
+ print "There are passages " + descList(exits) + "."
+ end if
+end function
+help.look = "Prints a description of the room and its contents."
+
+commands.quit = function(arg)
+ print "Quitter!"
+ globals.gameOver = true
+end function
+help.quit = "Quits the game."
+
+commands.take = function(obj)
+ roomStuff = getRoom.contents
+ items = roomStuff.withdraw(obj)
+ if items == null then
+ print "You don't see any " + obj + " here."
+ else
+ inventory.deposit items
+ print items.desc("You take")
+ end if
+end function
+help.take = "Picks up an item in the room; specify item name, or ""all""."
+
+// Command aliases:
+aliases = {"i":"inventory", "inv":"inventory", "l":"look", "get":"take"}
+
+// Main game loop
+gameOver = false
+commands.look
+while not gameOver
+ cmd = input(">").split(" ", 2)
+ if cmd.len == 1 then cmd.push null
+ verb = cmd[0]
+ if aliases.hasIndex(verb) then verb = aliases[verb]
+ if commands.hasIndex(verb) then
+ f = commands[verb]
+ f cmd[1]
+ else if dirAbbrevs.hasIndex(verb) or dir.hasIndex(verb) then
+ commands.go verb
+ else
+ print "Invalid command. For help, enter: help"
+ end if
+end while \ No newline at end of file