兩周自制腳本語(yǔ)言-第8天 關(guān)聯(lián)Java語(yǔ)言

第8天 關(guān)聯(lián)Java語(yǔ)言

本章要達(dá)到的目的:擴(kuò)展Stone語(yǔ)言请毛,使它能在程序中調(diào)用Java語(yǔ)言中的static方法

8.1 原生函數(shù)

Java語(yǔ)言提供了名為原生方法的功能,用于調(diào)用C語(yǔ)言等其他一些語(yǔ)言寫(xiě)成的函數(shù)鲤氢。我們將為Stone語(yǔ)言添加類(lèi)似的功能茴她,讓它能夠調(diào)用由Java語(yǔ)言寫(xiě)成的函數(shù)宇整。

原生函數(shù)將由Arguments類(lèi)的eval方法調(diào)用档叔。
代碼清單8.1是用于改寫(xiě)Arguments類(lèi)的eval方法的修改器桌粉。
這個(gè)名為NativeArgEx的修改器標(biāo)有extendsArgumentsEx一句,它修改的是Arguments類(lèi)衙四。
ArgumentsEx是第7天代碼清單7.7中定義的另一個(gè)修改器铃肯。NativeArgEx修改器與ArgumentsEx修改器都有用于修改Arguments類(lèi),它將在后者的基礎(chǔ)上對(duì)該類(lèi)作進(jìn)一步修改传蹈。

這里的修改器繼承了另一個(gè)修改器押逼。

通過(guò)這次修改,Arguments類(lèi)eval方法將首先判斷參數(shù)value是否為NativeFunction對(duì)象惦界。參數(shù)value是一個(gè)由函數(shù)調(diào)用表達(dá)式的函數(shù)名得到的對(duì)象挑格。eval方法之前返回的總是Function對(duì)象。如果參數(shù)是一個(gè)NativeFunction對(duì)象表锻,eval方法將在計(jì)算實(shí)參序列并保存至數(shù)組args之后恕齐,調(diào)用NativeFunction對(duì)象的invoke來(lái)執(zhí)行目標(biāo)函數(shù)。如果參數(shù)不是NativeFunction對(duì)象瞬逊,解釋器將執(zhí)行通常的函數(shù)調(diào)用。
它將通過(guò)super來(lái)調(diào)用原先由ArgumentsEx修改器添加的eval方法仪或。

代碼清單8.1 NativeEvaluator.java

package chap8;
import java.util.List;
import stone.StoneException;
import stone.ast.ASTree;
import javassist.gluonj.*;
import chap6.Environment;
import chap6.BasicEvaluator.ASTreeEx;
import chap7.FuncEvaluator;

@Require(FuncEvaluator.class)
@Reviser
public class NativeEvaluator {
    @Reviser
    public static class NativeArgEx extends FuncEvaluator.ArgumentsEx {
        public NativeArgEx(List<ASTree> c) {
            super(c);
        }

        public Object eval(Environment callerEnv, Object value) {
            if (!(value instanceof NativeFunction))
                return super.eval(callerEnv, value);
            NativeFunction func = (NativeFunction) value;
            int nparams = func.numOfParameters();
            if (size() != nparams)
                throw new StoneException("bad number of arguments", this);
            Object[] args = new Object[nparams];
            int num = 0;
            for (ASTree a : this) {
                ASTreeEx ae = (ASTreeEx) a;
                args[num++] = ae.eval(callerEnv);
            }
            return func.invoke(args, this);
        }
    }
}

代碼清單8.2是NativeFunction類(lèi)确镊。如果函數(shù)是一個(gè)原生函數(shù),程序?qū)⒃陂_(kāi)始執(zhí)行前創(chuàng)建NativeFunction類(lèi)的對(duì)象范删,將由函數(shù)名與相應(yīng)對(duì)象組成的名值對(duì)添加至環(huán)境中蕾域。該類(lèi)的invoke方法將以參數(shù)args為參數(shù)調(diào)用Java語(yǔ)言的static方法。

Method對(duì)象的invoke方法用于執(zhí)行它表示的Java語(yǔ)言方法。invoke的第1個(gè)參數(shù)是執(zhí)行該方法的對(duì)象旨巷。如果被執(zhí)行的是一個(gè)static方法巨缘,該參數(shù)則為null。invoke的第2個(gè)參數(shù)用于保存?zhèn)鬟f給方法的實(shí)參序列

代碼清單8.2 NativeFunction.java

package chap8;
import java.lang.reflect.Method;
import stone.StoneException;
import stone.ast.ASTree;

public class NativeFunction {
    protected Method method;
    protected String name;
    protected int numParams;

    public NativeFunction(String n, Method m) {
        name = n;
        method = m;
        numParams = m.getParameterTypes().length;
    }

    public String toString() {
        return "<native:" + hashCode() + ">";
    }

    public int numOfParameters() {
        return numParams;
    }

    public Object invoke(Object[] args, ASTree tree) {
        try {
            return method.invoke(null, args);
        } catch (Exception e) {
            throw new StoneException("bad native function call: " + name, tree);
        }
    }
}

代碼清單8.3中的程序會(huì)在執(zhí)行前創(chuàng)建NativeFunction對(duì)象采呐,并添加至環(huán)境中若锁。其中,Natives類(lèi)的environment方法將在調(diào)用后返回一個(gè)含有原生函數(shù)的環(huán)境斧吐。

append方法能夠向環(huán)境添加一個(gè)由參數(shù)指定的static方法作為原生函數(shù)又固。它的第3個(gè)參數(shù)是需要添加的static方法的類(lèi),第四個(gè)參數(shù)是該方法的名稱(chēng)煤率,從第五個(gè)參數(shù)開(kāi)始是該方法的參數(shù)類(lèi)型仰冠。如果新增的方法不含參數(shù),則僅需向append方法傳入前4個(gè)參數(shù)蝶糯。

代碼清單8.3向環(huán)境添加了print函數(shù)洋只、read函數(shù)、1ength函數(shù)昼捍、toInt函數(shù)以及currentTime函數(shù)木张。關(guān)于這些原生函數(shù)的用途,請(qǐng)參見(jiàn)Natives類(lèi)中的同名static方法端三。

代碼清單8.4與代碼清單8.5分別是解釋器程序及其啟動(dòng)程序舷礼。代碼清單8.4中的解釋器將首先調(diào)用Natives類(lèi)的environment方法,創(chuàng)建一個(gè)包含原生函數(shù)的環(huán)境郊闯。

8.2 編寫(xiě)使用原生函數(shù)的程序

代碼清單8.3 Natives.java

package chap8;
import java.lang.reflect.Method;
import javax.swing.JOptionPane;
import stone.StoneException;
import chap6.Environment;

public class Natives {
    public Environment environment(Environment env) {
        appendNatives(env);
        return env;
    }
    protected void appendNatives(Environment env) {
        append(env, "print", Natives.class, "print", Object.class);
        append(env, "read", Natives.class, "read");
        append(env, "length", Natives.class, "length", String.class);
        append(env, "toInt", Natives.class, "toInt", Object.class);
        append(env, "currentTime", Natives.class, "currentTime");
    }
    protected void append(Environment env, String name, Class<?> clazz,
                          String methodName, Class<?> ... params) {
        Method m;
        try {
            m = clazz.getMethod(methodName, params);
        } catch (Exception e) {
            throw new StoneException("cannot find a native function: "
                                     + methodName);
        }
        env.put(name, new NativeFunction(methodName, m));
    }

    // native methods
    public static int print(Object obj) {
        System.out.println(obj.toString());
        return 0;
    }
    public static String read() {
        return JOptionPane.showInputDialog(null);
    }
    public static int length(String s) { return s.length(); }
    public static int toInt(Object value) {
        if (value instanceof String)
            return Integer.parseInt((String)value);
        else if (value instanceof Integer)
            return ((Integer)value).intValue();
        else
            throw new NumberFormatException(value.toString());
    }
    private static long startTime = System.currentTimeMillis();
    public static int currentTime() {
        return (int)(System.currentTimeMillis() - startTime);
    }
}

代碼清單8.4 NativeInterpreter.java

package chap8;
import stone.ClosureParser;
import stone.ParseException;
import chap6.BasicInterpreter;
import chap7.NestedEnv;

public class NativeInterpreter extends BasicInterpreter {
    public static void main(String[] args) throws ParseException {
        run(new ClosureParser(),new Natives().environment(new NestedEnv()));
    }
}

代碼清單8.5 NativeRunner.java

package chap8;
import javassist.gluonj.util.Loader;
import chap7.ClosureEvaluator;

public class NativeRunner {
    public static void main(String[] args) throws Throwable {
        Loader.run(NativeInterpreter.class, args, NativeEvaluator.class,
                   ClosureEvaluator.class);
    }
}

代碼清單8.6 計(jì)算斐波那契數(shù)列所需的時(shí)間

def fib (n) {
    if n < 2 {
        n
    } else {
        fib (n - 1) + fib (n - 2)
    }
}
t = currentTime()
fib 15
print currentTime() - t + " msec"
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末妻献,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子团赁,更是在濱河造成了極大的恐慌育拨,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件欢摄,死亡現(xiàn)場(chǎng)離奇詭異熬丧,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)怀挠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)析蝴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人绿淋,你說(shuō)我怎么就攤上這事闷畸。” “怎么了吞滞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵佑菩,是天一觀的道長(zhǎng)盾沫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)殿漠,這世上最難降的妖魔是什么赴精? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮绞幌,結(jié)果婚禮上蕾哟,老公的妹妹穿的比我還像新娘。我一直安慰自己啊奄,他們只是感情好渐苏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著菇夸,像睡著了一般琼富。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上庄新,一...
    開(kāi)封第一講書(shū)人閱讀 51,598評(píng)論 1 305
  • 那天鞠眉,我揣著相機(jī)與錄音,去河邊找鬼择诈。 笑死械蹋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的羞芍。 我是一名探鬼主播哗戈,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼荷科!你這毒婦竟也來(lái)了唯咬?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤畏浆,失蹤者是張志新(化名)和其女友劉穎胆胰,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體刻获,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜀涨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蝎毡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厚柳。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖顶掉,靈堂內(nèi)的尸體忽然破棺而出草娜,到底是詐尸還是另有隱情,我是刑警寧澤痒筒,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響簿透,放射性物質(zhì)發(fā)生泄漏移袍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一老充、第九天 我趴在偏房一處隱蔽的房頂上張望葡盗。 院中可真熱鬧,春花似錦啡浊、人聲如沸觅够。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)喘先。三九已至,卻和暖如春廷粒,著一層夾襖步出監(jiān)牢的瞬間窘拯,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工坝茎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涤姊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓嗤放,卻偏偏與公主長(zhǎng)得像思喊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子次酌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容