{"id":15521896,"url":"https://github.com/crossoverjie/gscript","last_synced_at":"2025-04-13T06:41:34.627Z","repository":{"id":41529647,"uuid":"495480798","full_name":"crossoverJie/gscript","owner":"crossoverJie","description":"💪🏻This is a statically and strongly typed language written in Go.|GScript 是用 Go 编写的静态、强类型的脚本语言。","archived":false,"fork":false,"pushed_at":"2022-11-08T07:51:02.000Z","size":2861,"stargazers_count":222,"open_issues_count":2,"forks_count":24,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-26T23:08:27.704Z","etag":null,"topics":["antlr4","compile","go","golang","language","programming-language"],"latest_commit_sha":null,"homepage":"https://gscript.crossoverjie.top/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/crossoverJie.png","metadata":{"files":{"readme":"README-ZH.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-23T16:02:29.000Z","updated_at":"2025-03-18T01:55:41.000Z","dependencies_parsed_at":"2022-08-10T02:35:42.355Z","dependency_job_id":null,"html_url":"https://github.com/crossoverJie/gscript","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crossoverJie%2Fgscript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crossoverJie%2Fgscript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crossoverJie%2Fgscript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/crossoverJie%2Fgscript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/crossoverJie","download_url":"https://codeload.github.com/crossoverJie/gscript/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248675434,"owners_count":21143763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["antlr4","compile","go","golang","language","programming-language"],"created_at":"2024-10-02T10:38:27.553Z","updated_at":"2025-04-13T06:41:34.606Z","avatar_url":"https://github.com/crossoverJie.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e  \n\n\n```\n _     _   \n ___ ___ ___ ___|_|___| |_ \n| . |_ -|  _|  _| | . |  _|\n|_  |___|___|_| |_|  _|_|  \n|___|             |_|   \n\n```\n\n🎮[Play](#playground) | 📘[特性](#特性) | 🌰[例子](#例子) | 🔧[安装](#安装) | 👾[REPL](#repl) | 🎉[语法](#语法) | 🎁[标准库](#标准库) | 💡[联系作者](#联系作者) | 🇦🇺[英文文档](https://github.com/crossoverjie/gscript/blob/main/README.md)\n\n\n\u003c/div\u003e\u003cbr\u003e\n\n\n# 介绍\n\n这是一门用 `Go` 编写的一款**静态、强类型**的脚本语言，大部分语法参考了 `Java` 以及少量的 `Go`。\n\n## 目标\n提供类似于以脚本形式编写 Go 语言的能力，保留 Go 语言优点（goroutine等）,新增更多易用性的语法糖。\n\n\u003e 当前为 Alpha 版本仅供学习与实验。\n\n运行：\n\nhello_world.gs:\n```js\nprintln(\"hello world\");\n```\n\n```shell\n❯ gscript hello_world.gs\nhello world\n```\n\n# Playground\n\n在线地址: [https://gscript.crossoverjie.top/](https://gscript.crossoverjie.top/)\n\n源码地址: [https://github.com/crossoverJie/gscript-homepage](https://github.com/crossoverJie/gscript-homepage)\n\n![](doc/playground-min.gif)\n\n# 特性\n- [x] [class声明](#class)\n- [x] [函数声明与调用](#函数)\n- [x] [基本类型](#基本类型): `int/string/float/bool/byte`\n- [x] [array数组类型](#数组)\n- [x] `any` [通用类型](#any)\n- [x] 特殊类型 `nil`\n- [x] 函数类型\n- [x] [闭包：函数一等公民](#闭包)\n- [x] [内置函数](#内置函数)\n- [x] [标准库](#标准库)\n\t- [x] [Map](#map)\n- [x] [可变参数](#可变参数)\n- [x] [运算符重载](#运算符重载)\n- [x] [原生 `json` 支持](#内置函数)\n- [x] [原生 `http` 包支持](#http)\n- [x] 案例\n\t- [x] LeetCode\n\t\t- [x] [判断链表是否有环 ](https://github.com/crossoverJie/gscript/blob/main/example/linked_list_cycle141.gs)\n\t\t- [x] [两数之和](https://github.com/crossoverJie/gscript/blob/main/example/leetcode/two_sum.gs)\n\t- [x] [打印斐波那契数列 ](#打印斐波那契数列)\n\t- [x] [打印杨辉三角 ](#杨辉三角)\n\t- [x] [HTTP Service](https://github.com/crossoverJie/gscript/blob/main/example/http_server.gs)\n-  [ ] 包管理\n-  [ ] 单测命令行工具\n\n# 例子\n\n## Hello world\n```js\nprintln(\"hello world\");\n```\n\n## 打印斐波那契数列\n\n```js\nfunc int() fib(){\n    int a = 0;\n    int b = 1;\n    int fibonacci(){\n        int c = a;\n        a = b;\n        b = a+c;\n        return c;\n    }\n    return fibonacci;\n}\n\nfunc int() f = fib();\n\nfor (int i = 0; i \u003c 10; i++){\n    println(f());\n}\n```\n\n## 网站应用\n\n这是用 `GScript` 编写的动态网页：\n\n[https://gscript.crossoverjie.top/api/index](https://gscript.crossoverjie.top/api/index)\n\n源码地址：\n[https://github.com/crossoverjie/gscript-homepage](https://github.com/crossoverjie/gscript-homepage)\n\n## 杨辉三角\n\n```js\nint num(int x,int y){\n\tif (y==1 || y ==x) {\n\t\treturn 1;\n\t}\n    int v1 = num(x - 1, y - 1);\n    int v2 = num(x - 1, y);\n\tint c = v1+v2;\n    // int c = num(x - 1, y - 1)+num(x - 1, y);\n\treturn c;\n}\n\nprintTriangle(int row){\n\tfor (int i = 1; i \u003c= row; i++) {\n        for (int j = 1; j \u003c= row - i; j++) {\n           print(\" \");\n        }\n        for (int j = 1; j \u003c= i; j++) {\n            print(num(i, j) + \" \");\n        }\n        println(\"\");\n    }\n}\n\nprintTriangle(7);\n\n// output:\n      1 \n     1 1 \n    1 2 1 \n   1 3 3 1 \n  1 4 6 4 1 \n 1 5 10 10 5 1 \n1 6 15 20 15 6 1\n```\n\n---\n\n更多例子：[https://github.com/crossoverJie/gscript/tree/main/example](https://github.com/crossoverJie/gscript/tree/main/example)\n\n# 安装\n\n## 二进制文件\n\n在这里下载最新的二进制文件 [here](https://github.com/crossoverJie/gscript/releases)\n\n## 🐳Docker\n\n```shell\ndocker pull crossoverjie/gscript\n```\n\n### REPL\n```shell\ndocker run --rm -it  crossoverjie/gscript:latest gscript\n```\n\n### 运行脚本\n```shell\ndocker run --rm -v $PWD:/usr/src/gscript -w /usr/src/gscript crossoverjie/gscript gscript {yourpath}/temp.gs\n```\n\n## 源码构建\n\n```shell\ngit clone https://github.com/crossoverJie/gscript.git\ncd gscript\nmake build-code\n./gscript\n```\n\n# REPL\n```shell\n\u003e ./gscript \n```\n\n![](doc/repl.gif)\n\n# 语法\n\n## 基本类型\n\n当前版本支持 `int/string/float/bool` 四种基本类型以及 `nil` 特殊类型。\n\n变量声明语法：`type identifier (= expr)?`。\n\n```js\nint a=10;\nstring b,c;\nfloat e = 10.1;\nbool f = false;\nbyte by = 1;\nstring x = ^\n{\n    \"name\": \"bob\",\n    \"age\": 20,\n    \"skill\": {\n        \"lang\": [\n            {\n                \"go\": {\n                    \"feature\": [\n                        \"goroutine\",\n                        true\n                    ]\n                }\n            }\n        ]\n    }\n}^;\n```\n\n## 数组\n数组声明语法：`('[' DECIMAL_LITERAL ']')? '{' (variableInitializer (',' variableInitializer)* (',')? )? '}'`\n```js\n// 声明并初始化\nint[] a={1,2,3};\nprintln(a);\n\n// 声明一个空数组并指定大小\nint[] table = [4]{};\n\nprintln(\"\");\n// 向数组 append 数据\na = append(a,4);\nprintln(a);\nfor(int i=0;i\u003clen(a);i++){\n\tprintln(a[i]);\n}\n\n// 通过下标获取数组数据\nint b=a[2];\nprintln(b);\n\n\n// byte array\nstring s = \"10\";\nbyte[] a= toByteArray(s);\nprintf(\"a=%v \",a);\nstring s1 = toString(a);\nprintf(\"s1=%s\",s1);\nassertEqual(s1,s);\n\n// 将数组切片为新的数组\n// slice an array into a new array.\nint[] a = {1,2,3};\nint s=1;\nint[] b = a[s:len(a)];\nprintln(b);\n// output: [2 3]\n```\n\n## any\n\n`any` 是通用类型，类似于 Java 中的 Object 和 Go 中的 `interface{}`。\n\n```js\nany a =10;\nprintln(a);\n\nint fun1(any a,int b){\n\treturn a+b;\n}\nint v =fun1(1,2);\nprintln(v);\nassertEqual(v,3);\n\nany v2 = fun1(1,2);\nprintln(v2);\nassertEqual(v2,3);\n\nint fun2(int a, any b){\n\treturn a+b;\n}\nint v3 =fun2(1,2);\nprintln(v3);\nassertEqual(v3,3);\n\nint fun3(any a, any b){\n\treturn a+b;\n}\nint v4 =fun3(1,2);\nprintln(v4);\nassertEqual(v4,3);\n\nint fun4(any a, any b){\n\treturn a+b;\n}\nstring v5 =fun4(\"10\", \"20\");\nprintln(v5);\nassertEqual(v5,\"1020\");\n```\n\n[标准库](https://github.com/crossoverJie/gscript/blob/main/internal/internal.gs#L25)中有相关应用。\n## Class\n\n自定义 Class 与 Java 类似：\n\n```js\nclass ListNode{\n    int value;\n    ListNode next;\n    ListNode(int v, ListNode n){\n        value =v;\n        next = n;\n    }\n}\n\n// 调用构造函数时不需要使用 new 关键字。\nListNode l1 = ListNode(1, nil);\n\n// 使用 . 调用对象属性或函数。\nprintln(l1.value);\n```\n\n缺省情况下 `class` 具有无参构造函数：\n\n```js\nclass Person{\n\tint age=10;\n\tstring name=\"abc\";\n\tint getAge(){\n\t\treturn 100+age;\n\t}\n}\n\n// 无参构造函数\nPerson xx= Person();\nprintln(xx.age);\nassertEqual(xx.age, 10);\nprintln(xx.getAge());\nassertEqual(xx.getAge(), 110);\n```\n\n\n## 函数\n\n```js\n// 判断链表是否有环\nbool hasCycle(ListNode head){\n    if (head == nil){\n        return false;\n    }\n    if (head.next == nil){\n        return false;\n    }\n\n    ListNode fast = head.next;\n    ListNode slow = head;\n    bool ret = false;\n    for (fast.next != nil){\n        if (fast.next == nil){\n            return false;\n        }\n        if (fast.next.next == nil){\n            return false;\n        }\n        if (slow.next == nil){\n            return false;\n        }\n        if (fast == slow){\n            ret = true;\n            return true;\n        }\n\n        fast = fast.next.next;\n        slow = slow.next;\n    }\n    return ret;\n}\n\nListNode l1 = ListNode(1, nil);\nbool b1 =hasCycle(l1);\nprintln(b1);\nassertEqual(b1, false);\n\nListNode l4 = ListNode(4, nil);\nListNode l3 = ListNode(3, l4);\nListNode l2 = ListNode(2, l3);\nbool b2 = hasCycle(l2);\nprintln(b2);\nassertEqual(b2, false);\n\nl4.next = l2;\nbool b3 = hasCycle(l2);\nprintln(b3);\nassertEqual(b3, true);\n```\n\n函数声明语法：`typeTypeOrVoid? IDENTIFIER formalParameters ('[' ']')*`\n\n```js\nadd(int a){}\n```\n\n\u003e 当函数没有返回值时，可以声明为 void 或直接忽略返回类型。\n\n\n## 闭包\n\n在 `GScript` 中，函数作为一等公民可以作为变量传递，同时也能实现闭包。\n\n函数类型语法：`func typeTypeOrVoid '(' typeList? ')'`\n\n```js\n// 外部变量，全局共享。\nint varExternal =10;\nfunc int(int) f1(){\n\t// 闭包变量对每个闭包单独可见\n\tint varInner = 20;\n\tint innerFun(int a){\n\t\tprintln(a);\n\t\tint c=100;\n\t\tvarExternal++;\n\t\tvarInner++;\n\t\treturn varInner;\n\t}\n\treturn innerFun;\n}\n\n// f2 作为一个函数类型，接收的是一个返回值和参数都是 int 的函数。\nfunc int(int) f2 = f1();\nfor(int i=0;i\u003c2;i++){\n\tprintln(\"varInner=\" + f2(i) + \", varExternal=\" + varExternal);\n}\nprintln(\"=======\");\nfunc int(int) f3 = f1();\nfor(int i=0;i\u003c2;i++){\n\tprintln(\"varInner=\" + f3(i) + \", varExternal=\" + varExternal);\n}\n```\n\n最终输出如下：\n\n```shell\n0\nvarInner=21, varExternal=11\n1\nvarInner=22, varExternal=12\n=======\n0\nvarInner=21, varExternal=13\n1\nvarInner=22, varExternal=14\n\n```\n\n## 可变参数\n\n`GScript` 支持函数定义可变参数，语法如下：\n\n```js\nint add(string s, int ...num){\n\tprintln(s);\n\tint sum = 0;\n\tfor(int i=0;i\u003clen(num);i++){\n\t\tint v = num[i];\n\t\tsum = sum+v;\n\t}\n\treturn sum;\n}\nint x = add(\"abc\", 1,2,3,4);\nprintln(x);\nassertEqual(x, 10);\n```\n\n\n## 运算符重载\n`GScript` 支持以下运算符重载：\n- `+-*/`\n- `== != \u003c \u003c= \u003e \u003e=`\n\n\u003e 重载函数名称必须是 **operator**，名称后跟上运算符即可重载。\n\n```js\nclass Person{\n\tint age;\n\tPerson(int a){\n\t\tage = a;\n\t}\n}\nPerson operator + (Person p1, Person p2){\n\tPerson pp = Person(p1.age+p2.age);\n\treturn pp;\n}\nPerson operator - (Person p1, Person p2){\n\tPerson pp = Person(p1.age-p2.age);\n\treturn pp;\n}\nPerson operator * (Person p1, Person p2){\n\tPerson pp = Person(p1.age * p2.age);\n\treturn pp;\n}\nPerson operator / (Person p1, Person p2){\n\tPerson pp = Person(p1.age / p2.age);\n\treturn pp;\n}\nbool operator == (Person p1, Person p2){\n\treturn p1.age==p2.age;\n}\nbool operator != (Person p1, Person p2){\n\treturn p1.age!=p2.age;\n}\nbool operator \u003e (Person p1, Person p2){\n\treturn p1.age\u003ep2.age;\n}\nbool operator \u003e= (Person p1, Person p2){\n\treturn p1.age\u003e=p2.age;\n}\nbool operator \u003c (Person p1, Person p2){\n\treturn p1.age\u003cp2.age;\n}\nbool operator \u003c= (Person p1, Person p2){\n\treturn p1.age\u003c=p2.age;\n}\nPerson p1 = Person(10);\nPerson p2 = Person(20);\n//Person p3 =  operator(p1,p2);\nPerson p3 = p1+p2;\nprintln(\"p3.age=\"+p3.age);\nassertEqual(p3.age, 30);\n\nPerson p4 = p1-p2;\nprintln(\"p4.age=\"+p4.age);\nprintln(100-10);\n\nPerson p5 = p1*p2;\nprintln(\"p5.age=\"+p5.age);\nassertEqual(p5.age, 200);\n\nPerson p6 = p2/p1;\nprintln(\"p6.age=\"+p6.age);\nassertEqual(p6.age, 2);\n\nbool b1 = p1 == p2;\nprintln(\"b1==\"+b1);\nassertEqual(b1,false);\n\nbool b2 = p1 != p2;\nprintln(\"b2==\"+b2);\nassertEqual(b2,true);\n\nbool b3 = p1 \u003e p2;\nprintln(\"b3==\"+b3);\nassertEqual(b3,false);\n\nbool b4 = p1 \u003e= p2;\nprintln(\"b4==\"+b4);\nassertEqual(b4,false);\n\nbool b5 = p1 \u003c p2;\nprintln(\"b5==\"+b5);\nassertEqual(b5,true);\n\nbool b6 = p1 \u003c= p2;\nprintln(\"b6==\"+b6);\nassertEqual(b6,true);\n```\n\n\n更多样例请参考：[https://github.com/crossoverJie/gscript/tree/main/example](https://github.com/crossoverJie/gscript/tree/main/example)\n\n# 标准库\n\n标准库源码：[https://github.com/crossoverJie/gscript/tree/main/internal](https://github.com/crossoverJie/gscript/tree/main/internal)\n\n## 内置函数\n\n```js\n\nprintf(\"hello %s \",\"123\");\nprintf(\"hello-%s-%s \",\"123\",\"abc\");\nprintf(\"hello-%s-%d \",\"123\",123);\n\nstring s = sprintf(\"nice to meet %s\", \"you\");\nprintln(s);\nassertEqual(s,\"nice to meet you\");\n\nint[] a={1,2,3};\n// len 返回数组大小\nprintln(len(a));\n\n// 向数组追加数据\nappend(a,4);\nprintln(a);\n// output: [1,2,3,4]\n\n// 断言函数，不相等时会抛出运行时异常，并中断程序。\nassertEqual(len(a),4);\n\n// 返回 hashcode\nint hashcode = hash(key);\n\n// 序列化 JSON 字符串\nclass P{\n\tstring name;\n\tP(string n){\n\t\tname = n;\n\t}\n}\nclass Object{\n\tP p;\n\tint x;\n\tObject(P pp, int xx){\n\t\tp = pp;\n\t\tx = xx;\n\t}\n}\nP p1 = P(\"abc\");\nObject o1 = Object(p1, 100);\nstring json = JSON(o1);\nprintln(json); //{\"p\":{\"name\":\"abc\"},\"x\":100}\n\n// 查询 JSON\nint x = JSONGet(json,\"x\");\nprintln(x);\nassertEqual(x,100);\n\nstring name = JSONGet(json,\"p.name\");\nprintln(name);\nassertEqual(name,\"abc\");\n\n// 获取启动参数\nSystem s = System();\nstring[] args = s.getOSArgs();\n```\n\n\n\n\u003e 更多 JSON 查询语法请参考：[xjson](https://github.com/crossoverJie/xjson#arithmetic-syntax)\n\n# Map\n## 函数定义\n```js\nclass Map{\n\tput(any key, any value){}\n\tany get(any key){}\n}\n```\n\n## 用法\n\n```js\nint count =100;\nMap m1 = Map();\nfor (int i=0;i\u003ccount;i++){\n\tstring key = i+\"\";\n\tstring value = key;\n\tm1.put(key,value);\n}\nprintln(m1.getSize());\nassertEqual(m1.getSize(),count);\n\nfor (int i=0;i\u003ccount;i++){\n\tstring key = i+\"\";\n\tstring value = m1.get(key);\n\tprintln(\"key=\"+key+ \":\"+ value);\n\tassertEqual(key,value);\n}\n```\n\n\n# StringBuilder\n## 函数定义\n\n```java\nclass StringBuilder{\n\tbyte[] buf = [0]{};\n\n\t// append contents to buf, it returns the length of s\n\tint writeString(string s){}\n\n\t// append b to buf, it returns the length of b.\n\tint WriteBytes(byte[] b){}\n\n\t// copies the buffer to a new.\n\tgrow(int n){}\n\n\tstring String(){}\n}\n```\n\n## 用法\n```java\nStringBuilder b = StringBuilder();\nb.writeString(\"10\");\nb.writeString(\"20\");\nint l = b.writeString(\"30\");\nstring s = b.String();\nprintf(\"s:%s, len=%d \",s,l);\nassertEqual(s,\"102030\");\nbyte[] b2 = toByteArray(\"40\");\nb.WriteBytes(b2);\ns = b.String();\nassertEqual(s,\"10203040\");\nprintln(s);\n```\n\n# Strings\n## 函数定义\n\n```java\nclass Strings{\n\t// concatenates the elements of its first argument to create a single string. The separator\n\t// string sep is placed between elements in the resulting string.\n\tstring join(string[] elems, string sep){}\n\n\t// tests whether the string s begins with prefix.\n\tbool hasPrefix(string s, string prefix){}\n}\n```\n\n## 用法\n\n```java\nStrings s = Strings();\nstring[] elems = {\"name=xxx\",\"age=xx\"};\nstring ret = s.join(elems, \"\u0026\");\nprintln(ret);\nassertEqual(ret, \"name=xxx\u0026age=xx\");\n\nbool b = s.hasPrefix(\"http://www.xx.com\", \"http\");\nprintln(b);\nassertEqual(b,true);\nb = s.hasPrefix(\"http://www.xx.com\", \"https\");\nprintln(b);\nassertEqual(b,false);\n```\n\n# http\n标准库定义：\n\n```js\n// http lib\n// Response json\nFprintfJSON(int code, string path, string json){}\n// Resonse html\nFprintfHTML(int code, string path, string html){}\n\n// path (relative paths may omit leading slash)\nstring QueryPath(string path){}\n\nstring FormValue(string path, string key){}\nclass HttpContext{\n    string path;\n    JSON(int code, any v){\n        string json = JSON(v);\n        FprintfJSON(code, path, json);\n    }\n    HTML(int code, any v) {\n        string html = v;\n        FprintfHTML(code, path, html);\n    }\n    string queryPath() {\n        string p = QueryPath(path);\n        return p;\n    }\n\n    string formValue(string key){\n        string v = FormValue(path, key);\n        return v;\n    }\n}\n// Bind route\nhttpHandle(string method, string path, func (HttpContext) handle){\n    // println(\"path=\"+path);\n    HttpContext ctx = HttpContext();\n    handle(ctx);\n}\n// Run http server.\nhttpRun(string addr){}\n```\n\n启动一个 `HTTP` 服务：\n\n```js\nclass Person{\n    string name;\n}\nfunc (HttpContext) handle (HttpContext ctx){\n    Person p = Person();\n    p.name = \"abc\";\n    println(\"p.name=\" + p.name);\n    println(\"ctx=\" + ctx);\n    ctx.JSON(200, p);\n}\n\nfunc (HttpContext) handle1 (HttpContext ctx){\n    Person p = Person();\n    p.name = \"def\";\n    println(\"p.name=\" + p.name);\n    println(\"ctx=\" + ctx);\n    ctx.JSON(200, p);\n}\nfunc (HttpContext) handle2 (HttpContext ctx){\n    DateTime d = DateTime();\n    string local = d.getCurrentTime(\"Asia/Shanghai\",\"2006-01-02 15:04:05\");\n    println(local);\n    string html =^\n    \u003chtml\u003e\n    \u003ctitle\u003ehello\u003c/title\u003e\n    \u003ch1\u003ecurrent ^+ local +^\u003c/h1\u003e\n    \u003cp\u003ehahaha\u003c/p\u003e\n    \u003c/html\u003e\n    ^;\n    string queryPath = ctx.queryPath();\n    println(\"queryPath = \" + queryPath);\n\n    // http://127.0.0.1:8000/p/2?id=100\n    string id = ctx.formValue(\"id\");\n    println(\"id=\"+id);\n    ctx.HTML(200, html);\n}\nhttpHandle(\"get\", \"/p\", handle);\nhttpHandle(\"get\", \"/p/1\", handle1);\nhttpHandle(\"get\", \"/p/2\", handle2);\nhttpRun(\":8000\");\n\n```\n\n\n\n## 联系作者\n\n\n\u003e crossoverJie#gmail.com\n\n![qrcode_for_gh_3a954a025f10_258.jpg](https://i.loli.net/2019/07/09/5d245f3e955ce61699.jpg) ","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrossoverjie%2Fgscript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrossoverjie%2Fgscript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrossoverjie%2Fgscript/lists"}