From 0240b76cc3fa5ab28dcb57befea1e9479c44c339 Mon Sep 17 00:00:00 2001 From: Gusakov Nikita Date: Tue, 15 Apr 2014 16:24:30 +0400 Subject: [PATCH] Added Zephir language --- lib/linguist/languages.yml | 8 +- lib/linguist/samples.json | 699 ++++++++++++++++++++++++++++++++++++- samples/Zephir/Cblock.zep | 53 +++ samples/Zephir/Router.zep | 557 +++++++++++++++++++++++++++++ 4 files changed, 1309 insertions(+), 8 deletions(-) create mode 100644 samples/Zephir/Cblock.zep create mode 100644 samples/Zephir/Router.zep diff --git a/lib/linguist/languages.yml b/lib/linguist/languages.yml index 6eb2a378..38b8d3af 100644 --- a/lib/linguist/languages.yml +++ b/lib/linguist/languages.yml @@ -606,7 +606,7 @@ Fancy: - .fancypack filenames: - Fakefile - + Fantom: type: programming color: "#dbded5" @@ -1938,6 +1938,12 @@ YAML: - .rviz - .yaml +Zephir: + type: programming + lexer: PHP + color: "#118f9e" + primary_extension: .zep + eC: type: programming search_term: ec diff --git a/lib/linguist/samples.json b/lib/linguist/samples.json index 6d26388a..849ea8fb 100644 --- a/lib/linguist/samples.json +++ b/lib/linguist/samples.json @@ -237,6 +237,9 @@ "Markdown": [ ".md" ], + "Mask": [ + ".mask" + ], "Matlab": [ ".m" ], @@ -417,6 +420,9 @@ ".sh", ".zsh" ], + "Shen": [ + ".shen" + ], "Slash": [ ".sl" ], @@ -488,6 +494,12 @@ ], "Xtend": [ ".xtend" + ], + "YAML": [ + ".yml" + ], + "Zephir": [ + ".zep" ] }, "interpreters": { @@ -551,8 +563,8 @@ ".gemrc" ] }, - "tokens_total": 450556, - "languages_total": 548, + "tokens_total": 455175, + "languages_total": 555, "tokens": { "ABAP": { "*/**": 1, @@ -30365,6 +30377,55 @@ "Markdown": { "Tender": 1 }, + "Mask": { + "header": 1, + "{": 10, + "img": 1, + ".logo": 1, + "src": 1, + "alt": 1, + "logo": 1, + ";": 3, + "h4": 1, + "if": 1, + "(": 3, + "currentUser": 1, + ")": 3, + ".account": 1, + "a": 1, + "href": 1, + "}": 10, + ".view": 1, + "ul": 1, + "for": 1, + "user": 1, + "index": 1, + "of": 1, + "users": 1, + "li.user": 1, + "data": 1, + "-": 3, + "id": 1, + ".name": 1, + ".count": 1, + ".date": 1, + "countdownComponent": 1, + "input": 1, + "type": 1, + "text": 1, + "dualbind": 1, + "value": 1, + "button": 1, + "x": 2, + "signal": 1, + "h5": 1, + "animation": 1, + "slot": 1, + "@model": 1, + "@next": 1, + "footer": 1, + "bazCompo": 1 + }, "Matlab": { "function": 34, "[": 311, @@ -44077,6 +44138,440 @@ "foodforthought.jpg": 1, "name##*fo": 1 }, + "Shen": { + "*": 47, + "graph.shen": 1, + "-": 747, + "a": 30, + "library": 3, + "for": 12, + "graph": 52, + "definition": 1, + "and": 16, + "manipulation": 1, + "Copyright": 2, + "(": 267, + "C": 6, + ")": 250, + "Eric": 2, + "Schulte": 2, + "***": 5, + "License": 2, + "Redistribution": 2, + "use": 2, + "in": 13, + "source": 4, + "binary": 4, + "forms": 2, + "with": 8, + "or": 2, + "without": 2, + "modification": 2, + "are": 7, + "permitted": 2, + "provided": 4, + "that": 3, + "the": 29, + "following": 6, + "conditions": 6, + "met": 2, + "Redistributions": 4, + "of": 20, + "code": 2, + "must": 4, + "retain": 2, + "above": 4, + "copyright": 4, + "notice": 4, + "this": 4, + "list": 32, + "disclaimer.": 2, + "form": 2, + "reproduce": 2, + "disclaimer": 2, + "documentation": 2, + "and/or": 2, + "other": 2, + "materials": 2, + "distribution.": 2, + "THIS": 4, + "SOFTWARE": 4, + "IS": 2, + "PROVIDED": 2, + "BY": 2, + "THE": 10, + "COPYRIGHT": 4, + "HOLDERS": 2, + "AND": 8, + "CONTRIBUTORS": 4, + "ANY": 8, + "EXPRESS": 2, + "OR": 16, + "IMPLIED": 4, + "WARRANTIES": 4, + "INCLUDING": 6, + "BUT": 4, + "NOT": 4, + "LIMITED": 4, + "TO": 4, + "OF": 16, + "MERCHANTABILITY": 2, + "FITNESS": 2, + "FOR": 4, + "A": 32, + "PARTICULAR": 2, + "PURPOSE": 2, + "ARE": 2, + "DISCLAIMED.": 2, + "IN": 6, + "NO": 2, + "EVENT": 2, + "SHALL": 2, + "HOLDER": 2, + "BE": 2, + "LIABLE": 2, + "DIRECT": 2, + "INDIRECT": 2, + "INCIDENTAL": 2, + "SPECIAL": 2, + "EXEMPLARY": 2, + "CONSEQUENTIAL": 2, + "DAMAGES": 2, + "PROCUREMENT": 2, + "SUBSTITUTE": 2, + "GOODS": 2, + "SERVICES": 2, + ";": 12, + "LOSS": 2, + "USE": 4, + "DATA": 2, + "PROFITS": 2, + "BUSINESS": 2, + "INTERRUPTION": 2, + "HOWEVER": 2, + "CAUSED": 2, + "ON": 2, + "THEORY": 2, + "LIABILITY": 4, + "WHETHER": 2, + "CONTRACT": 2, + "STRICT": 2, + "TORT": 2, + "NEGLIGENCE": 2, + "OTHERWISE": 2, + "ARISING": 2, + "WAY": 2, + "OUT": 2, + "EVEN": 2, + "IF": 2, + "ADVISED": 2, + "POSSIBILITY": 2, + "SUCH": 2, + "DAMAGE.": 2, + "Commentary": 2, + "Graphs": 1, + "represented": 1, + "as": 2, + "two": 1, + "dictionaries": 1, + "one": 2, + "vertices": 17, + "edges.": 1, + "It": 1, + "is": 5, + "important": 1, + "to": 16, + "note": 1, + "dictionary": 3, + "implementation": 1, + "used": 2, + "able": 1, + "accept": 1, + "arbitrary": 1, + "data": 17, + "structures": 1, + "keys.": 1, + "This": 1, + "structure": 2, + "technically": 1, + "encodes": 1, + "hypergraphs": 1, + "generalization": 1, + "graphs": 1, + "which": 1, + "each": 1, + "edge": 32, + "may": 1, + "contain": 2, + "any": 1, + "number": 12, + ".": 1, + "Examples": 1, + "regular": 1, + "G": 25, + "hypergraph": 1, + "H": 3, + "corresponding": 1, + "given": 4, + "below.": 1, + "": 3, + "Vertices": 11, + "Edges": 9, + "+": 33, + "Graph": 65, + "hash": 8, + "|": 103, + "key": 9, + "value": 17, + "b": 13, + "c": 11, + "g": 19, + "[": 93, + "]": 91, + "d": 12, + "e": 14, + "f": 10, + "Hypergraph": 1, + "h": 3, + "i": 3, + "j": 2, + "associated": 1, + "edge/vertex": 1, + "@p": 17, + "V": 48, + "#": 4, + "E": 20, + "edges": 17, + "M": 4, + "vertex": 29, + "associations": 1, + "size": 2, + "all": 3, + "stored": 1, + "dict": 39, + "sizeof": 4, + "int": 1, + "indices": 1, + "into": 1, + "&": 1, + "Edge": 11, + "dicts": 3, + "entry": 2, + "storage": 2, + "Vertex": 3, + "Code": 1, + "require": 2, + "sequence": 2, + "datatype": 1, + "dictoinary": 1, + "vector": 4, + "symbol": 1, + "package": 2, + "add": 25, + "has": 5, + "neighbors": 8, + "connected": 21, + "components": 8, + "partition": 7, + "bipartite": 3, + "included": 2, + "from": 3, + "take": 2, + "drop": 2, + "while": 2, + "range": 1, + "flatten": 1, + "filter": 2, + "complement": 1, + "seperate": 1, + "zip": 1, + "indexed": 1, + "reduce": 3, + "mapcon": 3, + "unique": 3, + "frequencies": 1, + "shuffle": 1, + "pick": 1, + "remove": 2, + "first": 2, + "interpose": 1, + "subset": 3, + "cartesian": 1, + "product": 1, + "<-dict>": 5, + "contents": 1, + "keys": 3, + "vals": 1, + "make": 10, + "define": 34, + "X": 4, + "<-address>": 5, + "0": 1, + "create": 1, + "specified": 1, + "sizes": 2, + "}": 22, + "Vertsize": 2, + "Edgesize": 2, + "let": 9, + "absvector": 1, + "do": 8, + "address": 5, + "defmacro": 3, + "macro": 3, + "return": 4, + "taking": 1, + "optional": 1, + "N": 7, + "vert": 12, + "1": 1, + "2": 3, + "{": 15, + "get": 3, + "Value": 3, + "if": 8, + "tuple": 3, + "fst": 3, + "error": 7, + "string": 3, + "resolve": 6, + "Vector": 2, + "Index": 2, + "Place": 6, + "nth": 1, + "<-vector>": 2, + "Vert": 5, + "Val": 5, + "trap": 4, + "snd": 2, + "map": 5, + "lambda": 1, + "w": 4, + "B": 2, + "Data": 2, + "w/o": 5, + "D": 4, + "update": 5, + "an": 3, + "s": 1, + "Vs": 4, + "Store": 6, + "<": 4, + "limit": 2, + "VertLst": 2, + "/.": 4, + "Contents": 5, + "adjoin": 2, + "length": 5, + "EdgeID": 3, + "EdgeLst": 2, + "p": 1, + "boolean": 4, + "Return": 1, + "Already": 5, + "New": 5, + "Reachable": 2, + "difference": 3, + "append": 1, + "including": 1, + "itself": 1, + "fully": 1, + "Acc": 2, + "true": 1, + "_": 1, + "VS": 4, + "Component": 6, + "ES": 3, + "Con": 8, + "verts": 4, + "cons": 1, + "place": 3, + "partitions": 1, + "element": 2, + "simple": 3, + "CS": 3, + "Neighbors": 3, + "empty": 1, + "intersection": 1, + "check": 1, + "tests": 1, + "set": 1, + "chris": 6, + "patton": 2, + "eric": 1, + "nobody": 2, + "fail": 1, + "when": 1, + "wrapper": 1, + "function": 1, + "html.shen": 1, + "html": 2, + "generation": 1, + "functions": 1, + "shen": 1, + "The": 1, + "standard": 1, + "lisp": 1, + "conversion": 1, + "tool": 1, + "suite.": 1, + "Follows": 1, + "some": 1, + "convertions": 1, + "Clojure": 1, + "tasks": 1, + "stuff": 1, + "todo1": 1, + "today": 1, + "attributes": 1, + "AS": 1, + "load": 1, + "JSON": 1, + "Lexer": 1, + "Read": 1, + "stream": 1, + "characters": 4, + "Whitespace": 4, + "not": 1, + "strings": 2, + "should": 2, + "be": 2, + "discarded.": 1, + "preserved": 1, + "Strings": 1, + "can": 1, + "escaped": 1, + "double": 1, + "quotes.": 1, + "e.g.": 2, + "whitespacep": 2, + "ASCII": 2, + "Space.": 1, + "All": 1, + "others": 1, + "whitespace": 7, + "table.": 1, + "Char": 4, + "member": 1, + "replace": 3, + "@s": 4, + "Suffix": 4, + "where": 2, + "Prefix": 2, + "fetch": 1, + "until": 1, + "unescaped": 1, + "doublequote": 1, + "c#34": 5, + "WhitespaceChar": 2, + "Chars": 4, + "strip": 2, + "chars": 2, + "tokenise": 1, + "JSONString": 2, + "CharList": 2, + "explode": 1 + }, "Slash": { "<%>": 1, "class": 11, @@ -48459,7 +48954,7 @@ }, "YAML": { "gem": 1, - "-": 16, + "-": 25, "local": 1, "gen": 1, "rdoc": 2, @@ -48471,7 +48966,191 @@ "numbers": 1, "gempath": 1, "/usr/local/rubygems": 1, - "/home/gavin/.rubygems": 1 + "/home/gavin/.rubygems": 1, + "http_interactions": 1, + "request": 1, + "method": 1, + "get": 1, + "uri": 1, + "http": 1, + "//example.com/": 1, + "body": 3, + "headers": 2, + "{": 1, + "}": 1, + "response": 2, + "status": 1, + "code": 1, + "message": 1, + "OK": 1, + "Content": 2, + "Type": 1, + "text/html": 1, + ";": 1, + "charset": 1, + "utf": 1, + "Length": 1, + "This": 1, + "is": 1, + "the": 1, + "http_version": 1, + "recorded_at": 1, + "Tue": 1, + "Nov": 1, + "GMT": 1, + "recorded_with": 1, + "VCR": 1 + }, + "Zephir": { + "%": 10, + "{": 56, + "#define": 1, + "MAX_FACTOR": 3, + "}": 50, + "namespace": 3, + "Test": 2, + ";": 86, + "#include": 1, + "static": 1, + "long": 3, + "fibonacci": 4, + "(": 55, + "n": 5, + ")": 53, + "if": 39, + "<": 1, + "return": 25, + "else": 11, + "-": 25, + "+": 5, + "class": 2, + "Cblock": 1, + "public": 22, + "function": 22, + "testCblock1": 1, + "int": 3, + "a": 6, + "testCblock2": 1, + "Router": 1, + "Route": 1, + "protected": 9, + "_pattern": 3, + "_compiledPattern": 3, + "_paths": 3, + "_methods": 5, + "_hostname": 3, + "_converters": 3, + "_id": 2, + "_name": 3, + "_beforeMatch": 3, + "__construct": 1, + "pattern": 37, + "paths": 7, + "null": 11, + "httpMethods": 6, + "this": 28, + "reConfigure": 2, + "let": 51, + "compilePattern": 2, + "var": 4, + "idPattern": 6, + "memstr": 10, + "str_replace": 6, + ".": 5, + "via": 1, + "extractNamedParams": 2, + "string": 6, + "char": 1, + "ch": 27, + "tmp": 4, + "matches": 5, + "boolean": 1, + "notValid": 5, + "false": 3, + "cursor": 4, + "cursorVar": 5, + "marker": 4, + "bracketCount": 7, + "parenthesesCount": 5, + "foundPattern": 6, + "intermediate": 4, + "numberMatches": 4, + "route": 12, + "item": 7, + "variable": 5, + "regexp": 7, + "strlen": 1, + "<=>": 5, + "0": 9, + "for": 4, + "in": 4, + "1": 3, + "substr": 3, + "break": 9, + "&&": 6, + "z": 2, + "Z": 2, + "true": 2, + "<='9')>": 1, + "_": 1, + "2": 2, + "continue": 1, + "[": 14, + "]": 14, + "moduleName": 5, + "controllerName": 7, + "actionName": 4, + "parts": 9, + "routePaths": 5, + "realClassName": 1, + "namespaceName": 1, + "pcrePattern": 4, + "compiledPattern": 4, + "extracted": 4, + "typeof": 2, + "throw": 1, + "new": 1, + "Exception": 1, + "explode": 1, + "switch": 1, + "count": 1, + "case": 3, + "controller": 1, + "action": 1, + "array": 1, + "The": 1, + "contains": 1, + "invalid": 1, + "#": 1, + "array_merge": 1, + "//Update": 1, + "the": 1, + "s": 1, + "name": 5, + "*": 2, + "@return": 1, + "*/": 1, + "getName": 1, + "setName": 1, + "beforeMatch": 1, + "callback": 2, + "getBeforeMatch": 1, + "getRouteId": 1, + "getPattern": 1, + "getCompiledPattern": 1, + "getPaths": 1, + "getReversedPaths": 1, + "reversed": 4, + "path": 3, + "position": 3, + "setHttpMethods": 1, + "getHttpMethods": 1, + "setHostname": 1, + "hostname": 2, + "getHostname": 1, + "convert": 1, + "converter": 2, + "getConverters": 1 } }, "language_tokens": { @@ -48544,6 +49223,7 @@ "M": 23373, "Makefile": 50, "Markdown": 1, + "Mask": 74, "Matlab": 11942, "Max": 714, "MediaWiki": 766, @@ -48594,6 +49274,7 @@ "Scilab": 69, "SCSS": 39, "Shell": 3744, + "Shen": 3472, "Slash": 187, "Squirrel": 130, "Standard ML": 6405, @@ -48617,7 +49298,8 @@ "XQuery": 801, "XSLT": 44, "Xtend": 399, - "YAML": 30 + "YAML": 77, + "Zephir": 1026 }, "languages": { "ABAP": 1, @@ -48689,6 +49371,7 @@ "M": 28, "Makefile": 2, "Markdown": 1, + "Mask": 1, "Matlab": 39, "Max": 3, "MediaWiki": 1, @@ -48739,6 +49422,7 @@ "Scilab": 3, "SCSS": 1, "Shell": 37, + "Shen": 3, "Slash": 1, "Squirrel": 1, "Standard ML": 4, @@ -48762,7 +49446,8 @@ "XQuery": 1, "XSLT": 1, "Xtend": 2, - "YAML": 1 + "YAML": 2, + "Zephir": 2 }, - "md5": "cfe1841f5e4b2ab14a1ad53ad64523b8" + "md5": "48b917c2128d87edb0c72410ba183d14" } \ No newline at end of file diff --git a/samples/Zephir/Cblock.zep b/samples/Zephir/Cblock.zep new file mode 100644 index 00000000..43db8d7a --- /dev/null +++ b/samples/Zephir/Cblock.zep @@ -0,0 +1,53 @@ +/** + * CBLOCK tests + * asfas + */ + +%{ +// top statement before namespace, add to after headers +#define MAX_FACTOR 40 +}% + +namespace Test; + +%{ +// top statement before class, add to after headers +// test include .h +#include "kernel/require.h" +}% + +%{ + +// c implement fibonacci +static long fibonacci(long n) { + if (n < 2) return n; + else return fibonacci(n - 2) + fibonacci(n - 1); +} + +}% + +class Cblock +{ + public function testCblock1() + { + int a = 0; + + %{ + a = MAX_FACTOR; + }% + + return a; + } + + public function testCblock2() + { + long a = 0; + + %{ + a = fibonacci(MAX_FACTOR); + }% + + return a; + } + +} diff --git a/samples/Zephir/Router.zep b/samples/Zephir/Router.zep new file mode 100644 index 00000000..a8d4f907 --- /dev/null +++ b/samples/Zephir/Router.zep @@ -0,0 +1,557 @@ + +namespace Test\Router; + +/** + * Test\Router\Route + * + * This class represents every route added to the router + */ +class Route +{ + protected _pattern; + + protected _compiledPattern; + + protected _paths; + + protected _methods; + + protected _hostname; + + protected _converters; + + protected _id; + + protected _name; + + protected _beforeMatch; + + /** + * Test\Router\Route constructor + * + * @param string pattern + * @param array paths + * @param array|string httpMethods + */ + public function __construct(pattern, paths=null, httpMethods=null) + { + // Configure the route (extract parameters, paths, etc) + this->reConfigure(pattern, paths); + + // Update the HTTP method constraints + let this->_methods = httpMethods; + } + + /** + * Replaces placeholders from pattern returning a valid PCRE regular expression + * + * @param string pattern + * @return string + */ + public function compilePattern(pattern) + { + var idPattern; + + // If a pattern contains ':', maybe there are placeholders to replace + if memstr(pattern, ":") { + + // This is a pattern for valid identifiers + let idPattern = "/([a-zA-Z0-9\\_\\-]+)"; + + // Replace the module part + if memstr(pattern, "/:module") { + let pattern = str_replace("/:module", idPattern, pattern); + } + + // Replace the controller placeholder + if memstr(pattern, "/:controller") { + let pattern = str_replace("/:controller", idPattern, pattern); + } + + // Replace the namespace placeholder + if memstr(pattern, "/:namespace") { + let pattern = str_replace("/:namespace", idPattern, pattern); + } + + // Replace the action placeholder + if memstr(pattern, "/:action") { + let pattern = str_replace("/:action", idPattern, pattern); + } + + // Replace the params placeholder + if memstr(pattern, "/:params") { + let pattern = str_replace("/:params", "(/.*)*", pattern); + } + + // Replace the int placeholder + if memstr(pattern, "/:int") { + let pattern = str_replace("/:int", "/([0-9]+)", pattern); + } + } + + // Check if the pattern has parantheses in order to add the regex delimiters + if memstr(pattern, "(") { + return "#^" . pattern . "$#"; + } + + // Square brackets are also checked + if memstr(pattern, "[") { + return "#^" . pattern . "$#"; + } + + return pattern; + } + + /** + * Set one or more HTTP methods that constraint the matching of the route + * + * + * $route->via('GET'); + * $route->via(array('GET', 'POST')); + * + * + * @param string|array httpMethods + * @return Test\Router\Route + */ + public function via(httpMethods) + { + let this->_methods = httpMethods; + return this; + } + + /** + * Extracts parameters from a string + * + * @param string pattern + */ + public function extractNamedParams(string pattern) + { + + char ch; + var tmp, matches; + boolean notValid = false; + int cursor, cursorVar, marker, bracketCount = 0, parenthesesCount = 0, foundPattern = 0; + int intermediate = 0, numberMatches = 0; + string route, item, variable, regexp; + + if strlen(pattern) <= 0 { + return false; + } + + let matches = [], + route = ""; + + for cursor, ch in pattern { + + if parenthesesCount == 0 { + if ch == '{' { + if bracketCount == 0 { + let marker = cursor + 1, + intermediate = 0, + notValid = false; + } + let bracketCount++; + } else { + if ch == '}' { + let bracketCount--; + if intermediate > 0 { + if bracketCount == 0 { + + let numberMatches++, + variable = null, + regexp = null, + item = (string) substr(pattern, marker, cursor - marker); + + for cursorVar, ch in item { + + if ch == '\0' { + break; + } + + if cursorVar == 0 && !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { + let notValid = true; + break; + } + + if (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <='9') || ch == '-' || ch == '_' || ch == ':' { + if ch == ':' { + let variable = (string) substr(item, 0, cursorVar), + regexp = (string) substr(item, cursorVar + 1); + break; + } + } else { + let notValid = true; + break; + } + + } + + if !notValid { + + let tmp = numberMatches; + + if variable && regexp { + + let foundPattern = 0; + for ch in regexp { + if ch == '\0' { + break; + } + if !foundPattern { + if ch == '(' { + let foundPattern = 1; + } + } else { + if ch == ')' { + let foundPattern = 2; + break; + } + } + } + + if foundPattern != 2 { + let route .= '(', + route .= regexp, + route .= ')'; + } else { + let route .= regexp; + } + let matches[variable] = tmp; + } else { + let route .= "([^/]*)", + matches[item] = tmp; + } + } else { + let route .= "{" . item ."}"; + } + continue; + } + } + } + } + } + + if bracketCount == 0 { + if ch == '(' { + let parenthesesCount++; + } else { + if ch == ')' { + let parenthesesCount--; + if parenthesesCount == 0 { + let numberMatches++; + } + } + } + } + + if bracketCount > 0 { + let intermediate++; + } else { + let route .= ch; + } + } + + return [route, matches]; + } + + /** + * Reconfigure the route adding a new pattern and a set of paths + * + * @param string pattern + * @param array paths + */ + public function reConfigure(pattern, paths=null) + { + var moduleName, controllerName, actionName, + parts, routePaths, realClassName, namespaceName, + pcrePattern, compiledPattern, extracted; + + if typeof pattern != "string" { + throw new Exception("The pattern must be string"); + } + + if paths !== null { + if typeof paths == "string" { + + let moduleName = null, + controllerName = null, + actionName = null; + + // Explode the short paths using the :: separator + let parts = explode("::", paths); + + // Create the array paths dynamically + switch count(parts) { + case 3: + let moduleName = parts[0], + controllerName = parts[1], + actionName = parts[2]; + break; + case 2: + let controllerName = parts[0], + actionName = parts[1]; + break; + case 1: + let controllerName = parts[0]; + break; + } + + let routePaths = []; + + // Process module name + if moduleName !== null { + let routePaths["module"] = moduleName; + } + + // Process controller name + if controllerName !== null { + + // Check if we need to obtain the namespace + if memstr(controllerName, "\\") { + + // Extract the real class name from the namespaced class + let realClassName = get_class_ns(controllerName); + + // Extract the namespace from the namespaced class + let namespaceName = get_ns_class(controllerName); + + // Update the namespace + if namespaceName { + let routePaths["namespace"] = namespaceName; + } + } else { + let realClassName = controllerName; + } + + // Always pass the controller to lowercase + let routePaths["controller"] = uncamelize(realClassName); + } + + // Process action name + if actionName !== null { + let routePaths["action"] = actionName; + } + } else { + let routePaths = paths; + } + } else { + let routePaths = []; + } + + if typeof routePaths !== "array" { + throw new Exception("The route contains invalid paths"); + } + + // If the route starts with '#' we assume that it is a regular expression + if !starts_with(pattern, "#") { + + if memstr(pattern, "{") { + // The route has named parameters so we need to extract them + let extracted = this->extractNamedParams(pattern), + pcrePattern = extracted[0], + routePaths = array_merge(routePaths, extracted[1]); + } else { + let pcrePattern = pattern; + } + + // Transform the route's pattern to a regular expression + let compiledPattern = this->compilePattern(pcrePattern); + } else { + let compiledPattern = pattern; + } + + // Update the original pattern + let this->_pattern = pattern; + + // Update the compiled pattern + let this->_compiledPattern = compiledPattern; + + //Update the route's paths + let this->_paths = routePaths; + } + + /** + * Returns the route's name + * + * @return string + */ + public function getName() + { + return this->_name; + } + + /** + * Sets the route's name + * + * + * $router->add('/about', array( + * 'controller' => 'about' + * ))->setName('about'); + * + * + * @param string name + * @return Route + */ + public function setName(name) + { + let this->_name = name; + return this; + } + + /** + * Sets a callback that is called if the route is matched. + * The developer can implement any arbitrary conditions here + * If the callback returns false the route is treaded as not matched + * + * @param callback callback + * @return Test\Router\Route + */ + public function beforeMatch(callback) + { + let this->_beforeMatch = callback; + return this; + } + + /** + * Returns the 'before match' callback if any + * + * @return mixed + */ + public function getBeforeMatch() + { + return this->_beforeMatch; + } + + /** + * Returns the route's id + * + * @return string + */ + public function getRouteId() + { + return this->_id; + } + + /** + * Returns the route's pattern + * + * @return string + */ + public function getPattern() + { + return this->_pattern; + } + + /** + * Returns the route's compiled pattern + * + * @return string + */ + public function getCompiledPattern() + { + return this->_compiledPattern; + } + + /** + * Returns the paths + * + * @return array + */ + public function getPaths() + { + return this->_paths; + } + + /** + * Returns the paths using positions as keys and names as values + * + * @return array + */ + public function getReversedPaths() + { + var reversed, path, position; + + let reversed = []; + for path, position in this->_paths { + let reversed[position] = path; + } + return reversed; + } + + /** + * Sets a set of HTTP methods that constraint the matching of the route (alias of via) + * + * + * $route->setHttpMethods('GET'); + * $route->setHttpMethods(array('GET', 'POST')); + * + * + * @param string|array httpMethods + * @return Test\Router\Route + */ + public function setHttpMethods(httpMethods) + { + let this->_methods = httpMethods; + return this; + } + + /** + * Returns the HTTP methods that constraint matching the route + * + * @return string|array + */ + public function getHttpMethods() + { + return this->_methods; + } + + /** + * Sets a hostname restriction to the route + * + * + * $route->setHostname('localhost'); + * + * + * @param string|array httpMethods + * @return Test\Router\Route + */ + public function setHostname(hostname) + { + let this->_hostname = hostname; + return this; + } + + /** + * Returns the hostname restriction if any + * + * @return string + */ + public function getHostname() + { + return this->_hostname; + } + + /** + * Adds a converter to perform an additional transformation for certain parameter + * + * @param string name + * @param callable converter + * @return Test\Router\Route + */ + public function convert(name, converter) + { + let this->_converters[name] = converter; + return this; + } + + /** + * Returns the router converter + * + * @return array + */ + public function getConverters() + { + return this->_converters; + } + +}