<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          里程碑!用自己的編程語言實(shí)現(xiàn)了一個(gè)網(wǎng)站

          共 10527字,需瀏覽 22分鐘

           ·

          2022-09-17 17:21

          前言

          在上一篇《終于實(shí)現(xiàn)了一門屬于自己的編程語言》 介紹了自己寫的編程語言 GScript ,在文中提到希望最終可以使用 GScript 開發(fā)一個(gè)網(wǎng)站。

          到目前為止確實(shí)是做到了,首頁地址:

          https://gscript.crossoverjie.top/index

          要稱為一個(gè)網(wǎng)站確實(shí)有點(diǎn)勉強(qiáng),不過也是一個(gè)動(dòng)態(tài)網(wǎng)頁,因?yàn)榉祷氐氖?HTML,所以在當(dāng)前階段只要不嫌麻煩其實(shí)也能寫一個(gè)“合格”的網(wǎng)站,有點(diǎn)像以前我們學(xué)習(xí) Java 時(shí)的 servlet。

          該頁面的源碼地址在這里:https://github.com/crossoverjie/gscript-homepage

          其實(shí)總共也就40來行代碼:

          class GScript{
              string author;
              string[] features;
              string since;

              GScript(string a, string[] f, string s){
                  author = a;
                  features = f;
                  since = s;
              }
          }

          func (HttpContext) index(HttpContext ctx){
              string[] features = {"statically""strongly"};
              GScript gs = GScript("crossoverJie",features, "2022");
              string j = JSON(gs);
              println(j);
              string local = getCurrentTime("Asia/Shanghai","2006-01-02 15:04:05");
              println("local=" + local);
              string html = ^
                  <html>
                      <title>GScript</title>
                      <pre>
                           _     _   
           ___ ___ ___ ___|_|___| |_ 
          | . |_ -|  _|  _| | . |  _|
          |_  |___|___|_| |_|  _|_|  
          |___|             |_|   v0.0.7   

          ^+ j +^
                      </pre>
                      <h1>current ^+ local +^</h1>
                      <p><a href="https://github.com/crossoverjie/gscript-homepage">GScript-homepace source code</a></p>
                  </html>

              ^;
              ctx.HTML(200, html);
          }

          httpHandle("GET""/index", index);
          string[] args = getOSArgs();
          if (len(args) ==3){
              httpRun(":" + args[2]);
          }else {
              httpRun(":8000");
          }

          全是利用 GScript 所提供的標(biāo)準(zhǔn)庫實(shí)現(xiàn)的,后文會(huì)詳細(xì)聊聊內(nèi)置 HTTP 包。

          更新內(nèi)容

          下面重點(diǎn)來看看 v0.0.8 這個(gè)版本相較于上一個(gè)更新了哪些地方。

          因?yàn)槲沂前炎约寒?dāng)做一個(gè)開發(fā)者的角度去實(shí)現(xiàn)了一個(gè) http 服務(wù),同時(shí)還用 GScript 刷了兩道簡單的 LeetCode;為了讓這個(gè)過程更流暢,更符合一個(gè)現(xiàn)代語言的使用方式,所以本次真的更新不少東西。

          刷題源碼:https://github.com/crossoverJie/gscript/tree/main/example/leetcode

          大概如下:

          • any 類型的支持,簡化標(biāo)準(zhǔn)庫的實(shí)現(xiàn)。
          • 可以用 ^^ 來聲明多行字符串,方便聲明復(fù)雜字符串。
          • 更完善的類型推導(dǎo),修復(fù)了上個(gè)版本中某些情況推導(dǎo)不出類型的bug。
          • 支持運(yùn)算符重載。
          • 基本的 http 包,可以開發(fā)出 http 服務(wù),目前能響應(yīng) JSON 以及 HTML
          • 新增內(nèi)置函數(shù):根據(jù)時(shí)區(qū)獲取當(dāng)前時(shí)間、獲取應(yīng)用啟動(dòng)參數(shù)等。
          • JSON 的序列表以及查詢,語法級(jí)適配了 XJSON。
          • 修復(fù)了在多個(gè) block 嵌套情況下不能正確 return 的 bug。

          其實(shí)從這些更新中也能看出,上個(gè)版本只是一個(gè)簡單能用的狀態(tài),而現(xiàn)在這個(gè)版本已經(jīng)可以拿來寫復(fù)雜邏輯了,當(dāng)然目前還缺乏一些更友好的編譯提示以及運(yùn)行時(shí)錯(cuò)誤。

          下面仔細(xì)聊聊一些更新內(nèi)容。

          any 類型

          首先是 any 通用類型,這個(gè)類似于 Java 中的 Object 和 Go 中的 interface{},極大的方便了我們編寫一些標(biāo)準(zhǔn)庫。

          以之前內(nèi)置的 hash 和 len 函數(shù)為例,需要對(duì)每種類型都實(shí)現(xiàn)一遍,非常麻煩而且毫無必要;現(xiàn)在只需要定義一次即可,代碼量直接省幾倍。

          同理,之前實(shí)現(xiàn)的 Map 只支持存放 string 類型,現(xiàn)在便能存放任何類型的數(shù)據(jù)。

          對(duì) any 的實(shí)現(xiàn)過程感興趣的朋友,今后可以單獨(dú)分享一下。

          運(yùn)算符重載

          寫 go 或者是 Java 的朋友應(yīng)該知道,這兩門語言都無法對(duì)兩個(gè)對(duì)象進(jìn)行運(yùn)算,編譯器會(huì)直接報(bào)錯(cuò)。

          但在一些特殊場景下還是蠻好用的,于是我參考了 C# 的語法在 GScript 中也實(shí)現(xiàn)了。

          class Person{
           int age;
           Person(int a){
            age = a;
           }
          }
          Person operator + (Person p1, Person p2){
           Person pp = Person(p1.age+p2.age);
           return pp;
          }
          Person operator - (Person p1, Person p2){
           Person pp = Person(p1.age-p2.age);
           return pp;
          }
          Person p1 = Person(10);
          Person p2 = Person(20);
          Person p3 = p1+p2;
          println("p3.age="+p3.age);
          assertEqual(p3.age, 30);

          聲明的函數(shù)名稱必須為 operator,之后跟上運(yùn)算符便實(shí)現(xiàn)了重載。

          支持的運(yùn)算符有:+-*/ < >= <= > ==。

          JSON支持

          當(dāng)前版本中支持將對(duì)象、基本類型進(jìn)行序列化,暫不支持反序列化為對(duì)象,但可以根據(jù) JSON 字符串通過一定的語法查詢數(shù)據(jù)。

          內(nèi)置了兩個(gè) JSON 相關(guān)函數(shù):

          // return JSON string
          string JSON(any a){}
          // JSON query with path
          any JSONGet(string json, string path){}
          class Person{
           int age;
           string name;
           float weight;
           bool man;
           Person(string n, int a, float w, bool m){
            name = n;
            age = a;
            weight = w;
            man =m;
           }
          }
          Person p1 = Person("abc",10,99.99,true);
          Person p2 = Person("a",11,999.99,false);
          string json = JSON(p1);
          println(json);
          // output:{"age":10,"man":true,"name":"abc","weight":99.99}

          以這段代碼為例,調(diào)用 JSON 函數(shù)可以將對(duì)象序列化為 JSON 字符串。


          class Person{
           int age;
           string name;
           float weight;
           bool man;
           Person(string n, int a, float w, bool m){
            name = n;
            age = a;
            weight = w;
            man =m;
           }
          }
          Person p1 = Person("abc",10,99.99,true);
          string json = JSON(p1);
          println(json);

          int age = JSONGet(json, "age");
          println(age);
          assertEqual(age,10);

          使用 JSONGet 函數(shù)可以在一個(gè) JSON 字符串中查詢?nèi)我獾臄?shù)據(jù),這個(gè)功能是通過適配 XJSON 實(shí)現(xiàn)的,所以 XJSON 支持的查詢語法都能實(shí)現(xiàn)。

          string j=^{"age":10"abc":{"def":"def"},"list":[1,2,3]}^;
          String def = JSONGet(j, "abc.def");
          println(def);
          assertEqual(def,"def");
          int l1 = JSONGet(j, "list[0]");
          println(l1);
          assertEqual(l1,1);

          string str=^
          {
              "name""bob",
              "age"20,
              "skill": {
                  "lang": [
                      {
                          "go": {
                              "feature": [
                                  "goroutine",
                                  "channel",
                                  "simple",
                                  true
                              ]
                          }
                      }
                  ]
              }
          }
          ^;
          String g = JSONGet(str, "skill.lang[0].go.feature[0]");
          println(g);
          assertEqual(g,"goroutine");

          比如這樣復(fù)雜的嵌套 JSON,也能通過查詢語法獲取數(shù)據(jù)。

          HTTP 包

          HTTP 包是本次升級(jí)的重點(diǎn),標(biāo)準(zhǔn)庫中提供了以下函數(shù)和類:

          // http lib
          // Response json
          FprintfJSON(int code, string path, string json){}
          // Resonse html
          FprintfHTML(int code, string path, string html){}

          // path (relative paths may omit leading slash)
          string QueryPath(string path){}

          string FormValue(string path, string key){}
          class HttpContext{
              string path;
              JSON(int code, any v){
                  string json = JSON(v);
                  FprintfJSON(code, path, json);
              }
              HTML(int code, any v) {
                  string html = v;
                  FprintfHTML(code, path, html);
              }
              string queryPath() {
                  string p = QueryPath(path);
                  return p;
              }

              string formValue(string key){
                  string v = FormValue(path, key);
                  return v;
              }
          }
          // Bind route
          httpHandle(string method, string path, func (HttpContext) handle){
              // println("path="+path);
              HttpContext ctx = HttpContext();
              handle(ctx);
          }
          // Run http server.
          httpRun(string addr){}

          具體的使用流程:

          1. 通過定義一個(gè)函數(shù)變量實(shí)現(xiàn)自己的業(yè)務(wù)邏輯。
          2. 注冊(cè)路由。
          3. 啟動(dòng) HTTP 服務(wù)。

          在自己的 handle 中可以通過 HttpContext 對(duì)象拿到請(qǐng)求上下文,可以獲取請(qǐng)求參數(shù)以及響應(yīng)數(shù)據(jù)。具體使用示例可以參考這份代碼。

          總結(jié)

          本次更新比我預(yù)期的要順利一些,因?yàn)檎Z法樹和編譯器已經(jīng)基本實(shí)現(xiàn)完畢,不會(huì)怎么改了,現(xiàn)在新增的特性無非就是運(yùn)行時(shí)實(shí)現(xiàn)一些語法糖,大部分都是體力勞動(dòng);可能是新鮮感帶來的興奮劑效果,大部分時(shí)間都是痛并快樂著。

          比如這兩天主要就是在修復(fù)多層 block 嵌套時(shí)遇到 return 語句無法正確返回的 bug,死活折騰了兩夜;終于在無數(shù)次分析 AST 找到了解決方案,現(xiàn)在想想確實(shí)還是相關(guān)經(jīng)驗(yàn)太少。

          對(duì)這個(gè) Bug 感興趣的朋友可以點(diǎn)個(gè)贊,后面可以分享一下。

          下一階段重點(diǎn)就是將編譯信息好好整理,讓開發(fā)體驗(yàn)更好。之后抽空再把 SQL 標(biāo)準(zhǔn)庫實(shí)現(xiàn)了,這樣就能愉快的 CURD了。

          最后希望對(duì)該項(xiàng)目或者是編譯原理感興趣的朋友可以下載使用,提出寶貴意見,歡迎加我微信交流。

          v0.0.8 下載地址:https://github.com/crossoverJie/gscript/releases/tag/v0.0.8



          往期推薦



          終于實(shí)現(xiàn)了一門屬于自己的編程語言

          一門語言的作用域和函數(shù)調(diào)用是如何實(shí)現(xiàn)的

          用 Antlr 重構(gòu)腳本解釋器

          用位運(yùn)算為你的程序加速

          幾百行代碼實(shí)現(xiàn)一個(gè) JSON 解析器

           

          點(diǎn)分享

          點(diǎn)點(diǎn)贊

          點(diǎn)在看

           

          瀏覽 127
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天操网址 | 日韩AV中文字幕在线 | 日本一级电影在线 | 免费黄网站在线观看 | 国产乱伦中文字幕 |